From 71037c39a37d3549dcfe31926832a657744fbe05 Mon Sep 17 00:00:00 2001 From: Instrumental Date: Mon, 26 Mar 2018 13:51:48 -0700 Subject: [PATCH] AT&T 2.0.19 Code drop, stage 3 Issue-ID: AAF-197 Change-Id: I8b02cb073ccba318ccaf6ea0276446bdce88fb82 Signed-off-by: Instrumental --- auth/.gitignore | 12 + auth/auth-batch/.gitignore | 9 + auth/auth-batch/pom.xml | 129 + auth/auth-batch/src/main/config/.gitignore | 2 + .../src/main/java/org/onap/aaf/auth/Batch.java | 524 +++ .../java/org/onap/aaf/auth/BatchException.java | 51 + .../java/org/onap/aaf/auth/BatchPrincipal.java | 41 + .../src/main/java/org/onap/aaf/auth/CassBatch.java | 78 + .../java/org/onap/aaf/auth/actions/Action.java | 29 + .../java/org/onap/aaf/auth/actions/ActionDAO.java | 73 + .../org/onap/aaf/auth/actions/ActionPuntDAO.java | 72 + .../java/org/onap/aaf/auth/actions/CacheTouch.java | 53 + .../java/org/onap/aaf/auth/actions/CredDelete.java | 55 + .../java/org/onap/aaf/auth/actions/CredPrint.java | 56 + .../java/org/onap/aaf/auth/actions/CredPunt.java | 70 + .../main/java/org/onap/aaf/auth/actions/Email.java | 220 + .../java/org/onap/aaf/auth/actions/EmailPrint.java | 98 + .../org/onap/aaf/auth/actions/FuturePrint.java | 41 + .../main/java/org/onap/aaf/auth/actions/Key.java | 26 + .../java/org/onap/aaf/auth/actions/Message.java | 53 + .../java/org/onap/aaf/auth/actions/NSACreate.java | 58 + .../java/org/onap/aaf/auth/actions/NSADelete.java | 58 + .../org/onap/aaf/auth/actions/NSDescUpdate.java | 58 + .../java/org/onap/aaf/auth/actions/PermCreate.java | 69 + .../java/org/onap/aaf/auth/actions/PermDelete.java | 64 + .../java/org/onap/aaf/auth/actions/PermModify.java | 141 + .../java/org/onap/aaf/auth/actions/RoleCreate.java | 66 + .../java/org/onap/aaf/auth/actions/RoleDelete.java | 62 + .../java/org/onap/aaf/auth/actions/RoleModify.java | 152 + .../main/java/org/onap/aaf/auth/actions/URAdd.java | 57 + .../java/org/onap/aaf/auth/actions/URDelete.java | 59 + .../org/onap/aaf/auth/actions/URFutureApprove.java | 111 + .../onap/aaf/auth/actions/URFutureApproveExec.java | 108 + .../org/onap/aaf/auth/actions/URFuturePrint.java | 41 + .../java/org/onap/aaf/auth/actions/URModify.java | 80 + .../java/org/onap/aaf/auth/actions/URPrint.java | 42 + .../java/org/onap/aaf/auth/actions/URPunt.java | 70 + .../auth/entryConverters/AafEntryConverter.java | 46 + .../auth/entryConverters/CredEntryConverter.java | 48 + .../aaf/auth/entryConverters/NsEntryConverter.java | 46 + .../auth/entryConverters/PermEntryConverter.java | 43 + .../auth/entryConverters/RoleEntryConverter.java | 42 + .../entryConverters/UserRoleEntryConverter.java | 45 + .../java/org/onap/aaf/auth/helpers/Approval.java | 309 ++ .../java/org/onap/aaf/auth/helpers/Approver.java | 62 + .../org/onap/aaf/auth/helpers/CacheChange.java | 63 + .../java/org/onap/aaf/auth/helpers/Creator.java | 41 + .../main/java/org/onap/aaf/auth/helpers/Cred.java | 306 ++ .../java/org/onap/aaf/auth/helpers/Future.java | 200 + .../java/org/onap/aaf/auth/helpers/History.java | 178 + .../org/onap/aaf/auth/helpers/InputIterator.java | 69 + .../java/org/onap/aaf/auth/helpers/Loader.java | 26 + .../java/org/onap/aaf/auth/helpers/MiscID.java | 188 + .../java/org/onap/aaf/auth/helpers/MonthData.java | 121 + .../main/java/org/onap/aaf/auth/helpers/NS.java | 168 + .../org/onap/aaf/auth/helpers/Notification.java | 209 + .../java/org/onap/aaf/auth/helpers/NsAttrib.java | 107 + .../main/java/org/onap/aaf/auth/helpers/Perm.java | 172 + .../main/java/org/onap/aaf/auth/helpers/Role.java | 175 + .../java/org/onap/aaf/auth/helpers/UserRole.java | 282 ++ .../org/onap/aaf/auth/reports/ExpiringNext.java | 143 + .../java/org/onap/aaf/auth/update/Expiring.java | 503 +++ .../java/org/onap/aaf/auth/update/ExpiringP2.java | 158 + .../org/onap/aaf/auth/update/NotifyApprovals.java | 236 ++ .../onap/aaf/auth/update/NotifyCredExpiring.java | 321 ++ auth/auth-cass/.gitignore | 9 + auth/auth-cass/docker/dinstall | 29 + auth/auth-cass/pom.xml | 110 + auth/auth-cass/src/main/cql/.gitignore | 1 + auth/auth-cass/src/main/cql/keyspace.cql | 9 + auth/auth-cass/src/main/cql/osaaf.cql | 61 + auth/auth-cass/src/main/cql/temp_identity.cql | 8 + .../java/org/onap/aaf/auth/dao/AbsCassDAO.java | 504 +++ .../java/org/onap/aaf/auth/dao/Bytification.java | 30 + .../src/main/java/org/onap/aaf/auth/dao/CIDAO.java | 50 + .../main/java/org/onap/aaf/auth/dao/Cacheable.java | 34 + .../main/java/org/onap/aaf/auth/dao/Cached.java | 199 + .../main/java/org/onap/aaf/auth/dao/CachedDAO.java | 228 ++ .../java/org/onap/aaf/auth/dao/CassAccess.java | 223 + .../java/org/onap/aaf/auth/dao/CassDAOImpl.java | 348 ++ .../src/main/java/org/onap/aaf/auth/dao/DAO.java | 44 + .../java/org/onap/aaf/auth/dao/DAOException.java | 51 + .../main/java/org/onap/aaf/auth/dao/DAO_RO.java | 70 + .../main/java/org/onap/aaf/auth/dao/Loader.java | 214 + .../main/java/org/onap/aaf/auth/dao/Streamer.java | 31 + .../main/java/org/onap/aaf/auth/dao/Touchable.java | 26 + .../onap/aaf/auth/dao/cached/CachedCertDAO.java | 54 + .../onap/aaf/auth/dao/cached/CachedCredDAO.java | 66 + .../org/onap/aaf/auth/dao/cached/CachedNSDAO.java | 33 + .../onap/aaf/auth/dao/cached/CachedPermDAO.java | 124 + .../onap/aaf/auth/dao/cached/CachedRoleDAO.java | 106 + .../aaf/auth/dao/cached/CachedUserRoleDAO.java | 115 + .../java/org/onap/aaf/auth/dao/cass/.gitignore | 0 .../org/onap/aaf/auth/dao/cass/ApprovalDAO.java | 277 ++ .../java/org/onap/aaf/auth/dao/cass/ArtiDAO.java | 303 ++ .../org/onap/aaf/auth/dao/cass/CacheInfoDAO.java | 464 +++ .../org/onap/aaf/auth/dao/cass/CacheableData.java | 35 + .../java/org/onap/aaf/auth/dao/cass/CertDAO.java | 244 ++ .../java/org/onap/aaf/auth/dao/cass/CredDAO.java | 258 ++ .../org/onap/aaf/auth/dao/cass/DelegateDAO.java | 138 + .../java/org/onap/aaf/auth/dao/cass/FutureDAO.java | 183 + .../org/onap/aaf/auth/dao/cass/HistoryDAO.java | 238 ++ .../java/org/onap/aaf/auth/dao/cass/LocateDAO.java | 231 ++ .../java/org/onap/aaf/auth/dao/cass/Namespace.java | 150 + .../java/org/onap/aaf/auth/dao/cass/NsDAO.java | 560 +++ .../java/org/onap/aaf/auth/dao/cass/NsSplit.java | 61 + .../java/org/onap/aaf/auth/dao/cass/NsType.java | 74 + .../org/onap/aaf/auth/dao/cass/OAuthTokenDAO.java | 213 + .../java/org/onap/aaf/auth/dao/cass/PermDAO.java | 501 +++ .../java/org/onap/aaf/auth/dao/cass/RoleDAO.java | 412 ++ .../java/org/onap/aaf/auth/dao/cass/Status.java | 88 + .../org/onap/aaf/auth/dao/cass/UserRoleDAO.java | 319 ++ .../org/onap/aaf/auth/dao/hl/CassExecutor.java | 73 + .../java/org/onap/aaf/auth/dao/hl/Function.java | 1792 +++++++++ .../java/org/onap/aaf/auth/dao/hl/PermLookup.java | 185 + .../java/org/onap/aaf/auth/dao/hl/Question.java | 1154 ++++++ .../org/onap/aaf/auth/direct/DirectAAFLocator.java | 132 + .../org/onap/aaf/auth/direct/DirectAAFLur.java | 193 + .../onap/aaf/auth/direct/DirectAAFUserPass.java | 83 + .../onap/aaf/auth/direct/DirectCertIdentity.java | 78 + .../onap/aaf/auth/direct/DirectLocatorCreator.java | 59 + .../org/onap/aaf/auth/direct/DirectRegistrar.java | 106 + .../src/test/java/com/att/dao/aaf/test/.gitignore | 1 + .../test/java/com/att/dao/aaf/test/AbsJUCass.java | 200 + .../java/com/att/dao/aaf/test/JU_ApprovalDAO.java | 153 + .../test/java/com/att/dao/aaf/test/JU_ArtiDAO.java | 137 + .../java/com/att/dao/aaf/test/JU_Bytification.java | 266 ++ .../java/com/att/dao/aaf/test/JU_CacheInfoDAO.java | 64 + .../test/java/com/att/dao/aaf/test/JU_CertDAO.java | 103 + .../test/java/com/att/dao/aaf/test/JU_CredDAO.java | 250 ++ .../java/com/att/dao/aaf/test/JU_DelegateDAO.java | 108 + .../java/com/att/dao/aaf/test/JU_FastCalling.java | 90 + .../java/com/att/dao/aaf/test/JU_HistoryDAO.java | 153 + .../java/com/att/dao/aaf/test/JU_LocateDAO.java | 146 + .../com/att/dao/aaf/test/JU_LocationContent.java | 93 + .../test/java/com/att/dao/aaf/test/JU_NsDAO.java | 187 + .../test/java/com/att/dao/aaf/test/JU_NsType.java | 58 + .../com/att/dao/aaf/test/JU_OAuthTokenDAO.java | 134 + .../test/java/com/att/dao/aaf/test/JU_PermDAO.java | 176 + .../test/java/com/att/dao/aaf/test/JU_RoleDAO.java | 138 + .../java/com/att/dao/aaf/test/NS_ChildUpdate.java | 74 + .../org/onap/aaf/auth/cass/hl/JU_Question.java | 509 +++ .../org/onap/aaf/auth/cass/hl/JU_Question2.java | 73 + .../test/java/org/onap/aaf/auth/dao/JU_Cached.java | 124 + .../java/org/onap/aaf/auth/dao/JU_CachedDAO.java | 64 + .../java/org/onap/aaf/auth/dao/JU_CassAccess.java | 73 + .../java/org/onap/aaf/auth/dao/JU_CassDAOImpl.java | 96 + .../org/onap/aaf/auth/dao/JU_DAOException.java | 49 + .../org/onap/aaf/auth/dao/aaf/test/AbsJUCass.java | 200 + .../onap/aaf/auth/dao/aaf/test/JU_ApprovalDAO.java | 146 + .../org/onap/aaf/auth/dao/aaf/test/JU_ArtiDAO.java | 136 + .../aaf/auth/dao/aaf/test/JU_Bytification.java | 265 ++ .../aaf/auth/dao/aaf/test/JU_CacheInfoDAO.java | 63 + .../org/onap/aaf/auth/dao/aaf/test/JU_CertDAO.java | 103 + .../org/onap/aaf/auth/dao/aaf/test/JU_CredDAO.java | 250 ++ .../onap/aaf/auth/dao/aaf/test/JU_DelegateDAO.java | 106 + .../onap/aaf/auth/dao/aaf/test/JU_FastCalling.java | 89 + .../onap/aaf/auth/dao/aaf/test/JU_HistoryDAO.java | 153 + .../org/onap/aaf/auth/dao/aaf/test/JU_NsDAO.java | 185 + .../org/onap/aaf/auth/dao/aaf/test/JU_NsType.java | 58 + .../org/onap/aaf/auth/dao/aaf/test/JU_PermDAO.java | 174 + .../org/onap/aaf/auth/dao/aaf/test/JU_RoleDAO.java | 137 + .../onap/aaf/auth/direct/test/JU_DirectAAFLur.java | 63 + .../aaf/auth/direct/test/JU_DirectAAFUserPass.java | 84 + .../auth/direct/test/JU_DirectCertIdentity.java | 71 + auth/auth-certman/.gitignore | 6 + auth/auth-certman/pom.xml | 117 + auth/auth-certman/src/main/config/.gitignore | 1 + auth/auth-certman/src/main/config/certman.props | 22 + .../src/main/java/org/onap/aaf/auth/cm/AAF_CM.java | 239 ++ .../org/onap/aaf/auth/cm/api/API_Artifact.java | 134 + .../java/org/onap/aaf/auth/cm/api/API_Cert.java | 142 + .../src/main/java/org/onap/aaf/auth/cm/ca/CA.java | 209 + .../main/java/org/onap/aaf/auth/cm/ca/JscepCA.java | 268 ++ .../main/java/org/onap/aaf/auth/cm/ca/LocalCA.java | 182 + .../onap/aaf/auth/cm/ca/X509ChainWithIssuer.java | 74 + .../java/org/onap/aaf/auth/cm/ca/X509andChain.java | 79 + .../java/org/onap/aaf/auth/cm/cert/BCFactory.java | 151 + .../java/org/onap/aaf/auth/cm/cert/CSRMeta.java | 266 ++ .../main/java/org/onap/aaf/auth/cm/cert/RDN.java | 101 + .../java/org/onap/aaf/auth/cm/data/CertDrop.java | 26 + .../java/org/onap/aaf/auth/cm/data/CertRenew.java | 26 + .../java/org/onap/aaf/auth/cm/data/CertReq.java | 49 + .../java/org/onap/aaf/auth/cm/data/CertResp.java | 94 + .../java/org/onap/aaf/auth/cm/facade/Facade.java | 182 + .../org/onap/aaf/auth/cm/facade/Facade1_0.java | 46 + .../org/onap/aaf/auth/cm/facade/FacadeFactory.java | 41 + .../org/onap/aaf/auth/cm/facade/FacadeImpl.java | 643 +++ .../java/org/onap/aaf/auth/cm/mapper/Mapper.java | 54 + .../org/onap/aaf/auth/cm/mapper/Mapper1_0.java | 274 ++ .../org/onap/aaf/auth/cm/mapper/Mapper2_0.java | 268 ++ .../org/onap/aaf/auth/cm/service/CMService.java | 693 ++++ .../java/org/onap/aaf/auth/cm/service/Code.java | 45 + .../aaf/auth/cm/validation/CertmanValidator.java | 121 + auth/auth-certman/src/test/.gitignore | 1 + .../org/onap/aaf/auth/cm/api/JU_API_Artifact.java | 107 + .../java/org/onap/aaf/auth/cm/api/JU_API_Cert.java | 107 + .../java/org/onap/aaf/auth/cm/ca/JU_AppCA.java | 283 ++ .../java/org/onap/aaf/auth/cm/ca/JU_DevlCA.java | 280 ++ .../org/onap/aaf/auth/cm/cert/JU_BCFactory.java | 128 + .../java/org/onap/aaf/auth/cm/cert/JU_CSRMeta.java | 88 + .../java/org/onap/aaf/auth/cm/data/JU_CertReq.java | 90 + .../org/onap/aaf/auth/cm/facade/JU_FacadeImpl.java | 193 + .../org/onap/aaf/auth/cm/test/CertmanTest.java | 170 + .../onap/aaf/auth/cm/test/JU_KeyMarshaling.java | 80 + .../org/onap/aaf/auth/cm/test/JU_SignTest.java | 109 + auth/auth-client/.gitignore | 5 + auth/auth-client/pom.xml | 131 + auth/auth-client/src/main/xsd/aaf_2_0.xsd | 547 +++ auth/auth-client/src/main/xsd/aaf_oauth2.xsd | 141 + auth/auth-client/src/main/xsd/certman_1_0.xsd | 169 + auth/auth-client/src/main/xsd/certman_2_0.xsd | 169 + auth/auth-client/src/main/xsd/locate_1_0.xsd | 79 + auth/auth-cmd/.gitignore | 6 + auth/auth-cmd/pom.xml | 89 + .../main/java/org/onap/aaf/auth/cmd/AAFcli.java | 647 +++ .../main/java/org/onap/aaf/auth/cmd/BaseCmd.java | 68 + .../src/main/java/org/onap/aaf/auth/cmd/Cmd.java | 541 +++ .../java/org/onap/aaf/auth/cmd/DeprecatedCMD.java | 53 + .../src/main/java/org/onap/aaf/auth/cmd/Help.java | 118 + .../org/onap/aaf/auth/cmd/MessageException.java | 46 + .../src/main/java/org/onap/aaf/auth/cmd/Param.java | 37 + .../main/java/org/onap/aaf/auth/cmd/Version.java | 43 + .../java/org/onap/aaf/auth/cmd/mgmt/Cache.java | 32 + .../java/org/onap/aaf/auth/cmd/mgmt/Clear.java | 85 + .../main/java/org/onap/aaf/auth/cmd/mgmt/Deny.java | 101 + .../main/java/org/onap/aaf/auth/cmd/mgmt/Log.java | 108 + .../main/java/org/onap/aaf/auth/cmd/mgmt/Mgmt.java | 36 + .../java/org/onap/aaf/auth/cmd/mgmt/SessClear.java | 83 + .../java/org/onap/aaf/auth/cmd/mgmt/Session.java | 32 + .../main/java/org/onap/aaf/auth/cmd/ns/Admin.java | 103 + .../main/java/org/onap/aaf/auth/cmd/ns/Attrib.java | 113 + .../main/java/org/onap/aaf/auth/cmd/ns/Create.java | 123 + .../main/java/org/onap/aaf/auth/cmd/ns/Delete.java | 89 + .../java/org/onap/aaf/auth/cmd/ns/Describe.java | 94 + .../main/java/org/onap/aaf/auth/cmd/ns/List.java | 176 + .../org/onap/aaf/auth/cmd/ns/ListActivity.java | 80 + .../onap/aaf/auth/cmd/ns/ListAdminResponsible.java | 77 + .../java/org/onap/aaf/auth/cmd/ns/ListByName.java | 105 + .../org/onap/aaf/auth/cmd/ns/ListChildren.java | 81 + .../onap/aaf/auth/cmd/ns/ListNsKeysByAttrib.java | 88 + .../java/org/onap/aaf/auth/cmd/ns/ListUsers.java | 76 + .../org/onap/aaf/auth/cmd/ns/ListUsersContact.java | 128 + .../org/onap/aaf/auth/cmd/ns/ListUsersInRole.java | 128 + .../onap/aaf/auth/cmd/ns/ListUsersWithPerm.java | 128 + .../src/main/java/org/onap/aaf/auth/cmd/ns/NS.java | 45 + .../main/java/org/onap/aaf/auth/cmd/ns/Owner.java | 109 + .../java/org/onap/aaf/auth/cmd/perm/Create.java | 163 + .../java/org/onap/aaf/auth/cmd/perm/Delete.java | 89 + .../java/org/onap/aaf/auth/cmd/perm/Describe.java | 100 + .../java/org/onap/aaf/auth/cmd/perm/Grant.java | 150 + .../main/java/org/onap/aaf/auth/cmd/perm/List.java | 116 + .../org/onap/aaf/auth/cmd/perm/ListActivity.java | 76 + .../java/org/onap/aaf/auth/cmd/perm/ListByNS.java | 71 + .../org/onap/aaf/auth/cmd/perm/ListByName.java | 69 + .../org/onap/aaf/auth/cmd/perm/ListByRole.java | 72 + .../org/onap/aaf/auth/cmd/perm/ListByUser.java | 82 + .../main/java/org/onap/aaf/auth/cmd/perm/Perm.java | 42 + .../java/org/onap/aaf/auth/cmd/perm/Rename.java | 102 + .../org/onap/aaf/auth/cmd/role/CreateDelete.java | 130 + .../java/org/onap/aaf/auth/cmd/role/Describe.java | 94 + .../main/java/org/onap/aaf/auth/cmd/role/List.java | 211 + .../org/onap/aaf/auth/cmd/role/ListActivity.java | 75 + .../java/org/onap/aaf/auth/cmd/role/ListByNS.java | 72 + .../org/onap/aaf/auth/cmd/role/ListByNameOnly.java | 72 + .../org/onap/aaf/auth/cmd/role/ListByPerm.java | 78 + .../org/onap/aaf/auth/cmd/role/ListByRole.java | 69 + .../org/onap/aaf/auth/cmd/role/ListByUser.java | 99 + .../main/java/org/onap/aaf/auth/cmd/role/Role.java | 39 + .../main/java/org/onap/aaf/auth/cmd/role/User.java | 169 + .../main/java/org/onap/aaf/auth/cmd/user/Cred.java | 154 + .../main/java/org/onap/aaf/auth/cmd/user/Delg.java | 131 + .../main/java/org/onap/aaf/auth/cmd/user/List.java | 121 + .../org/onap/aaf/auth/cmd/user/ListActivity.java | 78 + .../org/onap/aaf/auth/cmd/user/ListApprovals.java | 102 + .../org/onap/aaf/auth/cmd/user/ListDelegates.java | 92 + .../org/onap/aaf/auth/cmd/user/ListForCreds.java | 100 + .../onap/aaf/auth/cmd/user/ListForPermission.java | 103 + .../org/onap/aaf/auth/cmd/user/ListForRoles.java | 92 + .../main/java/org/onap/aaf/auth/cmd/user/Role.java | 155 + .../main/java/org/onap/aaf/auth/cmd/user/User.java | 36 + .../java/org/onap/aaf/auth/cmd/test/JU_AAFCli.java | 198 + .../org/onap/aaf/auth/cmd/test/JU_BaseCmd.java | 243 ++ .../org/onap/aaf/auth/cmd/test/JU_BasicAuth.java | 53 + .../java/org/onap/aaf/auth/cmd/test/JU_Help.java | 97 + .../org/onap/aaf/auth/cmd/test/JU_Version.java | 64 + .../org/onap/aaf/auth/cmd/test/mgmt/JU_Clear.java | 61 + .../org/onap/aaf/auth/cmd/test/mgmt/JU_Log.java | 61 + .../onap/aaf/auth/cmd/test/mgmt/JU_SessClear.java | 61 + .../org/onap/aaf/auth/cmd/test/ns/JU_Admin.java | 71 + .../org/onap/aaf/auth/cmd/test/ns/JU_Attrib.java | 72 + .../org/onap/aaf/auth/cmd/test/ns/JU_Create.java | 72 + .../org/onap/aaf/auth/cmd/test/ns/JU_Delete.java | 76 + .../org/onap/aaf/auth/cmd/test/ns/JU_Describe.java | 77 + .../onap/aaf/auth/cmd/test/ns/JU_ListActivity.java | 74 + .../auth/cmd/test/ns/JU_ListAdminResponsible.java | 75 + .../onap/aaf/auth/cmd/test/ns/JU_ListByName.java | 74 + .../onap/aaf/auth/cmd/test/ns/JU_ListChildren.java | 74 + .../auth/cmd/test/ns/JU_ListNsKeysByAttrib.java | 74 + .../aaf/auth/cmd/test/ns/JU_ListUsersInRole.java | 76 + .../aaf/auth/cmd/test/ns/JU_ListUsersWithPerm.java | 76 + .../onap/aaf/auth/cmd/test/ns/JU_Responsible.java | 74 + .../org/onap/aaf/auth/cmd/test/perm/JU_Create.java | 73 + .../org/onap/aaf/auth/cmd/test/perm/JU_Delete.java | 73 + .../onap/aaf/auth/cmd/test/perm/JU_Describe.java | 73 + .../org/onap/aaf/auth/cmd/test/perm/JU_Grant.java | 73 + .../aaf/auth/cmd/test/perm/JU_ListActivity.java | 75 + .../onap/aaf/auth/cmd/test/perm/JU_ListByNS.java | 75 + .../onap/aaf/auth/cmd/test/perm/JU_ListByName.java | 75 + .../onap/aaf/auth/cmd/test/perm/JU_ListByRole.java | 75 + .../onap/aaf/auth/cmd/test/perm/JU_ListByUser.java | 75 + .../org/onap/aaf/auth/cmd/test/perm/JU_Rename.java | 73 + .../aaf/auth/cmd/test/role/JU_CreateDelete.java | 71 + .../onap/aaf/auth/cmd/test/role/JU_Describe.java | 71 + .../aaf/auth/cmd/test/role/JU_ListActivity.java | 73 + .../onap/aaf/auth/cmd/test/role/JU_ListByNS.java | 73 + .../aaf/auth/cmd/test/role/JU_ListByNameOnly.java | 73 + .../onap/aaf/auth/cmd/test/role/JU_ListByPerm.java | 73 + .../onap/aaf/auth/cmd/test/role/JU_ListByRole.java | 73 + .../onap/aaf/auth/cmd/test/role/JU_ListByUser.java | 73 + .../org/onap/aaf/auth/cmd/test/role/JU_User.java | 72 + .../org/onap/aaf/auth/cmd/test/user/JU_Cred.java | 124 + .../org/onap/aaf/auth/cmd/test/user/JU_Delg.java | 79 + .../aaf/auth/cmd/test/user/JU_ListActivity.java | 74 + .../aaf/auth/cmd/test/user/JU_ListApprovals.java | 74 + .../aaf/auth/cmd/test/user/JU_ListDelegates.java | 74 + .../aaf/auth/cmd/test/user/JU_ListForCreds.java | 74 + .../auth/cmd/test/user/JU_ListForPermission.java | 74 + .../aaf/auth/cmd/test/user/JU_ListForRoles.java | 74 + .../org/onap/aaf/auth/cmd/test/user/JU_Role.java | 72 + auth/auth-core/.gitignore | 5 + auth/auth-core/pom.xml | 104 + .../main/java/org/onap/aaf/auth/cache/Cache.java | 200 + .../main/java/org/onap/aaf/auth/common/Define.java | 82 + .../main/java/org/onap/aaf/auth/env/AuthzEnv.java | 310 ++ .../java/org/onap/aaf/auth/env/AuthzTrans.java | 78 + .../org/onap/aaf/auth/env/AuthzTransFilter.java | 181 + .../java/org/onap/aaf/auth/env/AuthzTransImpl.java | 216 + .../onap/aaf/auth/env/AuthzTransOnlyFilter.java | 86 + .../main/java/org/onap/aaf/auth/env/NullTrans.java | 234 ++ .../onap/aaf/auth/layer/DirectIntrospectImpl.java | 26 + .../java/org/onap/aaf/auth/layer/FacadeImpl.java | 42 + .../main/java/org/onap/aaf/auth/layer/Result.java | 328 ++ .../main/java/org/onap/aaf/auth/local/AbsData.java | 206 + .../java/org/onap/aaf/auth/local/DataFile.java | 190 + .../java/org/onap/aaf/auth/local/TextIndex.java | 256 ++ .../java/org/onap/aaf/auth/org/EmailWarnings.java | 33 + .../main/java/org/onap/aaf/auth/org/Executor.java | 34 + .../java/org/onap/aaf/auth/org/Organization.java | 515 +++ .../onap/aaf/auth/org/OrganizationException.java | 52 + .../org/onap/aaf/auth/org/OrganizationFactory.java | 125 + .../java/org/onap/aaf/auth/rserv/Acceptor.java | 169 + .../org/onap/aaf/auth/rserv/CachingFileAccess.java | 564 +++ .../java/org/onap/aaf/auth/rserv/CodeSetter.java | 52 + .../main/java/org/onap/aaf/auth/rserv/Content.java | 115 + .../java/org/onap/aaf/auth/rserv/HttpCode.java | 118 + .../java/org/onap/aaf/auth/rserv/HttpMethods.java | 29 + .../main/java/org/onap/aaf/auth/rserv/Match.java | 211 + .../main/java/org/onap/aaf/auth/rserv/Pair.java | 44 + .../java/org/onap/aaf/auth/rserv/RServlet.java | 154 + .../main/java/org/onap/aaf/auth/rserv/Route.java | 141 + .../java/org/onap/aaf/auth/rserv/RouteReport.java | 33 + .../main/java/org/onap/aaf/auth/rserv/Routes.java | 89 + .../java/org/onap/aaf/auth/rserv/TransFilter.java | 156 + .../org/onap/aaf/auth/rserv/TransOnlyFilter.java | 77 + .../java/org/onap/aaf/auth/rserv/TypedCode.java | 269 ++ .../main/java/org/onap/aaf/auth/rserv/Version.java | 93 + .../java/org/onap/aaf/auth/rserv/doc/ApiDoc.java | 40 + .../java/org/onap/aaf/auth/server/AbsService.java | 156 + .../onap/aaf/auth/server/AbsServiceStarter.java | 95 + .../onap/aaf/auth/server/JettyServiceStarter.java | 255 ++ .../org/onap/aaf/auth/server/ServiceStarter.java | 26 + .../org/onap/aaf/auth/validation/Validator.java | 204 + .../org/onap/aaf/auth/common/test/JU_Define.java | 66 + .../org/onap/aaf/auth/env/test/JU_AuthzEnv.java | 174 + .../aaf/auth/env/test/JU_AuthzTransFilter.java | 130 + .../onap/aaf/auth/env/test/JU_AuthzTransImpl.java | 169 + .../aaf/auth/env/test/JU_AuthzTransOnlyFilter.java | 121 + .../org/onap/aaf/auth/env/test/JU_NullTrans.java | 273 ++ .../org/onap/aaf/auth/layer/test/JU_Result.java | 58 + .../org/onap/aaf/auth/local/test/JU_DataFile.java | 70 + .../org/onap/aaf/auth/local/test/JU_TextIndex.java | 76 + .../auth/org/test/JU_OrganizationException.java | 48 + .../aaf/auth/org/test/JU_OrganizationFactory.java | 64 + .../onap/aaf/auth/request/test/CredCompare.java | 64 + .../aaf/auth/request/test/JU_RequestCheck.java | 42 + .../onap/aaf/auth/request/test/MultiCompare.java | 69 + .../aaf/auth/request/test/NSAttribCompare.java | 93 + .../org/onap/aaf/auth/request/test/NSCompare.java | 75 + .../onap/aaf/auth/request/test/PermCompare.java | 66 + .../onap/aaf/auth/request/test/RoleCompare.java | 62 + .../aaf/auth/request/test/RolePermCompare.java | 69 + .../onap/aaf/auth/request/test/RosettaCompare.java | 66 + .../aaf/auth/request/test/UserRoleCompare.java | 62 + .../onap/aaf/auth/rserv/test/JU_BetterMatch.java | 173 + .../onap/aaf/auth/rserv/test/JU_BetterMatch1.java | 164 + .../onap/aaf/auth/rserv/test/JU_BetterRoute.java | 33 + .../aaf/auth/rserv/test/JU_CachingFileAccess.java | 184 + .../onap/aaf/auth/rserv/test/JU_CodeSetter.java | 73 + .../org/onap/aaf/auth/rserv/test/JU_Content.java | 661 +++ .../org/onap/aaf/auth/rserv/test/JU_Content1.java | 130 + .../java/org/onap/aaf/auth/rserv/test/JU_Pair.java | 47 + .../org/onap/aaf/auth/rserv/test/JU_Route.java | 38 + .../onap/aaf/auth/rserv/test/JU_RouteReport.java | 40 + .../org/onap/aaf/auth/rserv/test/JU_Routes.java | 72 + .../org/onap/aaf/auth/rserv/test/JU_TypedCode.java | 106 + .../org/onap/aaf/auth/rserv/test/JU_Version.java | 70 + .../auth/server/test/JU_JettyServiceStarter.java | 95 + .../java/org/onap/aaf/auth/util/test/JU_Mask.java | 71 + .../aaf/auth/validation/test/JU_Validator.java | 204 + auth/auth-core/test/sample.identities.dat | 27 + auth/auth-deforg/.gitignore | 5 + auth/auth-deforg/pom.xml | 184 + .../src/main/java/org/onap/aaf/org/DefaultOrg.java | 666 +++ .../java/org/onap/aaf/org/DefaultOrgIdentity.java | 170 + .../java/org/onap/aaf/org/DefaultOrgWarnings.java | 63 + .../src/main/java/org/onap/aaf/org/Identities.java | 143 + .../java/org/onap/aaf/org/test/JU_DefaultOrg.java | 139 + .../onap/aaf/org/test/JU_DefaultOrgIdentity.java | 96 + .../onap/aaf/org/test/JU_DefaultOrgWarnings.java | 83 + .../java/org/onap/aaf/org/test/JU_Identities.java | 110 + auth/auth-deforg/src/test/resources/test.txt | 0 auth/auth-fs/.gitignore | 7 + auth/auth-fs/pom.xml | 122 + auth/auth-fs/src/main/config/.gitignore | 1 + auth/auth-fs/src/main/config/FileServer.props | 23 + auth/auth-fs/src/main/data/favicon.ico | Bin 0 -> 3638 bytes auth/auth-fs/src/main/data/test.html | 20 + .../src/main/java/org/onap/aaf/auth/fs/AAF_FS.java | 115 + .../org/onap/aaf/auth/fs/test/JU_FileServer.java | 81 + auth/auth-gui/.gitignore | 8 + auth/auth-gui/pom.xml | 142 + auth/auth-gui/src/main/config/.gitignore | 2 + .../src/main/java/org/onap/aaf/auth/cui/CUI.java | 93 + .../main/java/org/onap/aaf/auth/gui/AAF_GUI.java | 267 ++ .../java/org/onap/aaf/auth/gui/BreadCrumbs.java | 90 + .../java/org/onap/aaf/auth/gui/ContentCode.java | 36 + .../main/java/org/onap/aaf/auth/gui/Controls.java | 45 + .../main/java/org/onap/aaf/auth/gui/Display.java | 140 + .../src/main/java/org/onap/aaf/auth/gui/Form.java | 68 + .../main/java/org/onap/aaf/auth/gui/NamedCode.java | 67 + .../org/onap/aaf/auth/gui/OrgLookupFilter.java | 58 + .../src/main/java/org/onap/aaf/auth/gui/Page.java | 402 ++ .../main/java/org/onap/aaf/auth/gui/SlotCode.java | 49 + .../src/main/java/org/onap/aaf/auth/gui/Table.java | 229 ++ .../java/org/onap/aaf/auth/gui/XFrameFilter.java | 73 + .../java/org/onap/aaf/auth/gui/pages/ApiDocs.java | 334 ++ .../org/onap/aaf/auth/gui/pages/ApiExample.java | 133 + .../onap/aaf/auth/gui/pages/ApprovalAction.java | 121 + .../org/onap/aaf/auth/gui/pages/ApprovalForm.java | 299 ++ .../aaf/auth/gui/pages/CMArtiChangeAction.java | 219 + .../onap/aaf/auth/gui/pages/CMArtiChangeForm.java | 256 ++ .../onap/aaf/auth/gui/pages/CMArtifactShow.java | 251 ++ .../org/onap/aaf/auth/gui/pages/CredDetail.java | 352 ++ .../java/org/onap/aaf/auth/gui/pages/Home.java | 77 + .../org/onap/aaf/auth/gui/pages/LoginLanding.java | 115 + .../aaf/auth/gui/pages/LoginLandingAction.java | 65 + .../java/org/onap/aaf/auth/gui/pages/NsDetail.java | 247 ++ .../org/onap/aaf/auth/gui/pages/NsHistory.java | 230 ++ .../org/onap/aaf/auth/gui/pages/NsInfoAction.java | 158 + .../org/onap/aaf/auth/gui/pages/NsInfoForm.java | 162 + .../java/org/onap/aaf/auth/gui/pages/NssShow.java | 142 + .../onap/aaf/auth/gui/pages/PassChangeAction.java | 211 + .../onap/aaf/auth/gui/pages/PassChangeForm.java | 205 + .../onap/aaf/auth/gui/pages/PassDeleteAction.java | 88 + .../aaf/auth/gui/pages/PendingRequestsShow.java | 193 + .../org/onap/aaf/auth/gui/pages/PermDetail.java | 160 + .../onap/aaf/auth/gui/pages/PermGrantAction.java | 135 + .../org/onap/aaf/auth/gui/pages/PermGrantForm.java | 157 + .../org/onap/aaf/auth/gui/pages/PermHistory.java | 243 ++ .../org/onap/aaf/auth/gui/pages/PermsShow.java | 121 + .../org/onap/aaf/auth/gui/pages/RequestDetail.java | 190 + .../org/onap/aaf/auth/gui/pages/RoleDetail.java | 295 ++ .../onap/aaf/auth/gui/pages/RoleDetailAction.java | 188 + .../org/onap/aaf/auth/gui/pages/RoleHistory.java | 228 ++ .../org/onap/aaf/auth/gui/pages/RolesShow.java | 144 + .../onap/aaf/auth/gui/pages/UserRoleExtend.java | 99 + .../onap/aaf/auth/gui/pages/UserRoleRemove.java | 97 + .../org/onap/aaf/auth/gui/pages/WebCommand.java | 118 + .../java/org/onap/aaf/auth/gui/table/AbsCell.java | 48 + .../org/onap/aaf/auth/gui/table/ButtonCell.java | 45 + .../org/onap/aaf/auth/gui/table/CheckBoxCell.java | 66 + .../org/onap/aaf/auth/gui/table/RadioCell.java | 48 + .../java/org/onap/aaf/auth/gui/table/RefCell.java | 54 + .../org/onap/aaf/auth/gui/table/TableData.java | 56 + .../onap/aaf/auth/gui/table/TextAndRefCell.java | 43 + .../java/org/onap/aaf/auth/gui/table/TextCell.java | 49 + .../org/onap/aaf/auth/gui/table/TextInputCell.java | 54 + auth/auth-gui/theme/onap/AAF_details.png | Bin 0 -> 650 bytes auth/auth-gui/theme/onap/AAF_font_size.png | Bin 0 -> 1280 bytes auth/auth-gui/theme/onap/AAF_maximize.png | Bin 0 -> 593 bytes auth/auth-gui/theme/onap/AAFdownload.png | Bin 0 -> 1834 bytes auth/auth-gui/theme/onap/AAFemail.png | Bin 0 -> 2277 bytes auth/auth-gui/theme/onap/LF_Collab_footer_gray.png | Bin 0 -> 47307 bytes .../theme/onap/LF_Collab_footer_gray_stripe.png | Bin 0 -> 1374 bytes auth/auth-gui/theme/onap/LF_Collab_header_gray.png | Bin 0 -> 21018 bytes auth/auth-gui/theme/onap/ONAP_LOGO.png | Bin 0 -> 24268 bytes auth/auth-gui/theme/onap/aaf5.css | 588 +++ auth/auth-gui/theme/onap/aaf5Desktop.css | 92 + auth/auth-gui/theme/onap/aaf5iPhone.css | 38 + auth/auth-gui/theme/onap/comm.js | 21 + auth/auth-gui/theme/onap/common.js | 101 + auth/auth-gui/theme/onap/console.js | 272 ++ auth/auth-gui/theme/onap/favicon.ico | Bin 0 -> 3638 bytes auth/auth-gui/theme/onap/logo_onap.png | Bin 0 -> 11349 bytes auth/auth-gui/theme/onap/options_down.png | Bin 0 -> 833 bytes auth/auth-gui/theme/onap/options_up.png | Bin 0 -> 826 bytes auth/auth-hello/.gitignore | 8 + auth/auth-hello/pom.xml | 96 + auth/auth-hello/src/main/config/.gitignore | 2 + auth/auth-hello/src/main/config/hello.props | 29 + .../java/org/onap/aaf/auth/hello/AAF_Hello.java | 129 + .../java/org/onap/aaf/auth/hello/API_Hello.java | 88 + .../org/onap/aaf/auth/hello/test/HelloTester.java | 81 + auth/auth-locate/.gitignore | 6 + auth/auth-locate/pom.xml | 113 + auth/auth-locate/src/main/.gitignore | 0 auth/auth-locate/src/main/config/.gitignore | 2 + .../java/org/onap/aaf/auth/locate/AAF_Locate.java | 243 ++ .../org/onap/aaf/auth/locate/BasicAuthCode.java | 77 + .../java/org/onap/aaf/auth/locate/LocateCode.java | 44 + .../onap/aaf/auth/locate/api/API_AAFAccess.java | 259 ++ .../java/org/onap/aaf/auth/locate/api/API_Api.java | 97 + .../org/onap/aaf/auth/locate/api/API_Find.java | 132 + .../org/onap/aaf/auth/locate/api/API_Proxy.java | 163 + .../onap/aaf/auth/locate/facade/LocateFacade.java | 106 + .../auth/locate/facade/LocateFacadeFactory.java | 48 + .../aaf/auth/locate/facade/LocateFacadeImpl.java | 393 ++ .../aaf/auth/locate/facade/LocateFacade_1_0.java | 40 + .../org/onap/aaf/auth/locate/mapper/Mapper.java | 41 + .../onap/aaf/auth/locate/mapper/Mapper_1_0.java | 150 + .../aaf/auth/locate/service/LocateService.java | 33 + .../aaf/auth/locate/service/LocateServiceImpl.java | 122 + .../auth/locate/validation/LocateValidator.java | 141 + auth/auth-locate/src/main/xsd/locate_1_0.xsd | 122 + auth/auth-oauth/.gitignore | 5 + auth/auth-oauth/pom.xml | 108 + auth/auth-oauth/src/main/config/.gitignore | 1 + auth/auth-oauth/src/main/config/oauth.props | 26 + .../java/org/onap/aaf/auth/oauth/AAF_OAuth.java | 196 + .../org/onap/aaf/auth/oauth/DirectOAuthTAF.java | 224 ++ .../main/java/org/onap/aaf/auth/oauth/OACode.java | 45 + .../java/org/onap/aaf/auth/oauth/OAuth2Filter.java | 64 + .../onap/aaf/auth/oauth/OAuth2FormHttpTafResp.java | 65 + .../org/onap/aaf/auth/oauth/api/API_Token.java | 82 + .../aaf/auth/oauth/facade/DirectIntrospect.java | 29 + .../auth/oauth/facade/DirectIntrospectImpl.java | 57 + .../aaf/auth/oauth/facade/DirectOAFacadeImpl.java | 28 + .../org/onap/aaf/auth/oauth/facade/OAFacade.java | 67 + .../onap/aaf/auth/oauth/facade/OAFacade1_0.java | 47 + .../aaf/auth/oauth/facade/OAFacadeFactory.java | 47 + .../onap/aaf/auth/oauth/facade/OAFacadeImpl.java | 333 ++ .../org/onap/aaf/auth/oauth/mapper/Mapper.java | 47 + .../org/onap/aaf/auth/oauth/mapper/Mapper1_0.java | 225 ++ .../aaf/auth/oauth/mapper/MapperIntrospect.java | 29 + .../aaf/auth/oauth/mapper/MapperIntrospect1_0.java | 74 + .../aaf/auth/oauth/service/JSONPermLoader.java | 34 + .../auth/oauth/service/JSONPermLoaderFactory.java | 119 + .../onap/aaf/auth/oauth/service/OAuthService.java | 301 ++ .../org/onap/aaf/auth/oauth/service/OCreds.java | 33 + auth/auth-service/.gitignore | 15 + auth/auth-service/pom.xml | 144 + auth/auth-service/src/main/config/.gitignore | 2 + auth/auth-service/src/main/docker/.gitignore | 2 + .../org/onap/aaf/auth/service/AAF_Service.java | 227 ++ .../aaf/auth/service/AuthzCassServiceImpl.java | 4245 ++++++++++++++++++++ .../org/onap/aaf/auth/service/AuthzService.java | 768 ++++ .../main/java/org/onap/aaf/auth/service/Code.java | 44 + .../java/org/onap/aaf/auth/service/MayChange.java | 33 + .../org/onap/aaf/auth/service/api/API_Api.java | 92 + .../onap/aaf/auth/service/api/API_Approval.java | 106 + .../org/onap/aaf/auth/service/api/API_Creds.java | 285 ++ .../onap/aaf/auth/service/api/API_Delegate.java | 152 + .../org/onap/aaf/auth/service/api/API_History.java | 238 ++ .../org/onap/aaf/auth/service/api/API_Mgmt.java | 276 ++ .../org/onap/aaf/auth/service/api/API_Multi.java | 65 + .../java/org/onap/aaf/auth/service/api/API_NS.java | 395 ++ .../org/onap/aaf/auth/service/api/API_Perms.java | 297 ++ .../org/onap/aaf/auth/service/api/API_Roles.java | 337 ++ .../org/onap/aaf/auth/service/api/API_User.java | 133 + .../onap/aaf/auth/service/api/API_UserRole.java | 181 + .../onap/aaf/auth/service/facade/AuthzFacade.java | 269 ++ .../auth/service/facade/AuthzFacadeFactory.java | 55 + .../aaf/auth/service/facade/AuthzFacadeImpl.java | 2642 ++++++++++++ .../aaf/auth/service/facade/AuthzFacade_2_0.java | 63 + .../org/onap/aaf/auth/service/mapper/Mapper.java | 123 + .../onap/aaf/auth/service/mapper/Mapper_2_0.java | 875 ++++ .../auth/service/validation/ServiceValidator.java | 253 ++ .../src/main/resources/docker-compose/.gitignore | 2 + .../main/resources/docker-compose/data/.gitignore | 2 + .../main/resources/docker-compose/data/ecomp.cql | 169 + .../main/resources/docker-compose/data/init.cql | 242 ++ .../main/resources/docker-compose/data2/.gitignore | 1 + .../resources/docker-compose/wait_for_host_port.sh | 17 + .../src/main/resources/docker/.gitignore | 5 + .../auth-service/src/main/resources/etc/.gitignore | 3 + .../org/onap/aaf/auth/service/api/test/.gitignore | 1 + .../aaf/auth/service/api/test/JU_API_Approval.java | 68 + .../aaf/auth/service/api/test/JU_API_Creds.java | 80 + .../aaf/auth/service/api/test/JU_API_Delegate.java | 64 + .../aaf/auth/service/api/test/JU_API_History.java | 67 + .../aaf/auth/service/api/test/JU_API_Mgmt.java | 66 + .../onap/aaf/auth/service/api/test/JU_API_NS.java | 59 + .../aaf/auth/service/api/test/JU_API_Perms.java | 75 + .../aaf/auth/service/api/test/JU_API_Roles.java | 65 + .../aaf/auth/service/api/test/JU_API_User.java | 64 + .../aaf/auth/service/api/test/JU_API_UserRole.java | 60 + .../validation/test/JU_ServiceValidator.java | 102 + .../aaf/authz/service/mapper/JU_Mapper_2_0.java | 162 + auth/docker/Dockerfile | 25 + auth/docker/dbash | 1 + auth/docker/dbuild | 22 + auth/docker/drun | 37 + auth/pom.xml | 463 +++ 614 files changed, 84287 insertions(+) create mode 100644 auth/.gitignore create mode 100644 auth/auth-batch/.gitignore create mode 100644 auth/auth-batch/pom.xml create mode 100644 auth/auth-batch/src/main/config/.gitignore create mode 100644 auth/auth-batch/src/main/java/org/onap/aaf/auth/Batch.java create mode 100644 auth/auth-batch/src/main/java/org/onap/aaf/auth/BatchException.java create mode 100644 auth/auth-batch/src/main/java/org/onap/aaf/auth/BatchPrincipal.java create mode 100644 auth/auth-batch/src/main/java/org/onap/aaf/auth/CassBatch.java create mode 100644 auth/auth-batch/src/main/java/org/onap/aaf/auth/actions/Action.java create mode 100644 auth/auth-batch/src/main/java/org/onap/aaf/auth/actions/ActionDAO.java create mode 100644 auth/auth-batch/src/main/java/org/onap/aaf/auth/actions/ActionPuntDAO.java create mode 100644 auth/auth-batch/src/main/java/org/onap/aaf/auth/actions/CacheTouch.java create mode 100644 auth/auth-batch/src/main/java/org/onap/aaf/auth/actions/CredDelete.java create mode 100644 auth/auth-batch/src/main/java/org/onap/aaf/auth/actions/CredPrint.java create mode 100644 auth/auth-batch/src/main/java/org/onap/aaf/auth/actions/CredPunt.java create mode 100644 auth/auth-batch/src/main/java/org/onap/aaf/auth/actions/Email.java create mode 100644 auth/auth-batch/src/main/java/org/onap/aaf/auth/actions/EmailPrint.java create mode 100644 auth/auth-batch/src/main/java/org/onap/aaf/auth/actions/FuturePrint.java create mode 100644 auth/auth-batch/src/main/java/org/onap/aaf/auth/actions/Key.java create mode 100644 auth/auth-batch/src/main/java/org/onap/aaf/auth/actions/Message.java create mode 100644 auth/auth-batch/src/main/java/org/onap/aaf/auth/actions/NSACreate.java create mode 100644 auth/auth-batch/src/main/java/org/onap/aaf/auth/actions/NSADelete.java create mode 100644 auth/auth-batch/src/main/java/org/onap/aaf/auth/actions/NSDescUpdate.java create mode 100644 auth/auth-batch/src/main/java/org/onap/aaf/auth/actions/PermCreate.java create mode 100644 auth/auth-batch/src/main/java/org/onap/aaf/auth/actions/PermDelete.java create mode 100644 auth/auth-batch/src/main/java/org/onap/aaf/auth/actions/PermModify.java create mode 100644 auth/auth-batch/src/main/java/org/onap/aaf/auth/actions/RoleCreate.java create mode 100644 auth/auth-batch/src/main/java/org/onap/aaf/auth/actions/RoleDelete.java create mode 100644 auth/auth-batch/src/main/java/org/onap/aaf/auth/actions/RoleModify.java create mode 100644 auth/auth-batch/src/main/java/org/onap/aaf/auth/actions/URAdd.java create mode 100644 auth/auth-batch/src/main/java/org/onap/aaf/auth/actions/URDelete.java create mode 100644 auth/auth-batch/src/main/java/org/onap/aaf/auth/actions/URFutureApprove.java create mode 100644 auth/auth-batch/src/main/java/org/onap/aaf/auth/actions/URFutureApproveExec.java create mode 100644 auth/auth-batch/src/main/java/org/onap/aaf/auth/actions/URFuturePrint.java create mode 100644 auth/auth-batch/src/main/java/org/onap/aaf/auth/actions/URModify.java create mode 100644 auth/auth-batch/src/main/java/org/onap/aaf/auth/actions/URPrint.java create mode 100644 auth/auth-batch/src/main/java/org/onap/aaf/auth/actions/URPunt.java create mode 100644 auth/auth-batch/src/main/java/org/onap/aaf/auth/entryConverters/AafEntryConverter.java create mode 100644 auth/auth-batch/src/main/java/org/onap/aaf/auth/entryConverters/CredEntryConverter.java create mode 100644 auth/auth-batch/src/main/java/org/onap/aaf/auth/entryConverters/NsEntryConverter.java create mode 100644 auth/auth-batch/src/main/java/org/onap/aaf/auth/entryConverters/PermEntryConverter.java create mode 100644 auth/auth-batch/src/main/java/org/onap/aaf/auth/entryConverters/RoleEntryConverter.java create mode 100644 auth/auth-batch/src/main/java/org/onap/aaf/auth/entryConverters/UserRoleEntryConverter.java create mode 100644 auth/auth-batch/src/main/java/org/onap/aaf/auth/helpers/Approval.java create mode 100644 auth/auth-batch/src/main/java/org/onap/aaf/auth/helpers/Approver.java create mode 100644 auth/auth-batch/src/main/java/org/onap/aaf/auth/helpers/CacheChange.java create mode 100644 auth/auth-batch/src/main/java/org/onap/aaf/auth/helpers/Creator.java create mode 100644 auth/auth-batch/src/main/java/org/onap/aaf/auth/helpers/Cred.java create mode 100644 auth/auth-batch/src/main/java/org/onap/aaf/auth/helpers/Future.java create mode 100644 auth/auth-batch/src/main/java/org/onap/aaf/auth/helpers/History.java create mode 100644 auth/auth-batch/src/main/java/org/onap/aaf/auth/helpers/InputIterator.java create mode 100644 auth/auth-batch/src/main/java/org/onap/aaf/auth/helpers/Loader.java create mode 100644 auth/auth-batch/src/main/java/org/onap/aaf/auth/helpers/MiscID.java create mode 100644 auth/auth-batch/src/main/java/org/onap/aaf/auth/helpers/MonthData.java create mode 100644 auth/auth-batch/src/main/java/org/onap/aaf/auth/helpers/NS.java create mode 100644 auth/auth-batch/src/main/java/org/onap/aaf/auth/helpers/Notification.java create mode 100644 auth/auth-batch/src/main/java/org/onap/aaf/auth/helpers/NsAttrib.java create mode 100644 auth/auth-batch/src/main/java/org/onap/aaf/auth/helpers/Perm.java create mode 100644 auth/auth-batch/src/main/java/org/onap/aaf/auth/helpers/Role.java create mode 100644 auth/auth-batch/src/main/java/org/onap/aaf/auth/helpers/UserRole.java create mode 100644 auth/auth-batch/src/main/java/org/onap/aaf/auth/reports/ExpiringNext.java create mode 100644 auth/auth-batch/src/main/java/org/onap/aaf/auth/update/Expiring.java create mode 100644 auth/auth-batch/src/main/java/org/onap/aaf/auth/update/ExpiringP2.java create mode 100644 auth/auth-batch/src/main/java/org/onap/aaf/auth/update/NotifyApprovals.java create mode 100644 auth/auth-batch/src/main/java/org/onap/aaf/auth/update/NotifyCredExpiring.java create mode 100644 auth/auth-cass/.gitignore create mode 100644 auth/auth-cass/docker/dinstall create mode 100644 auth/auth-cass/pom.xml create mode 100644 auth/auth-cass/src/main/cql/.gitignore create mode 100644 auth/auth-cass/src/main/cql/keyspace.cql create mode 100644 auth/auth-cass/src/main/cql/osaaf.cql create mode 100644 auth/auth-cass/src/main/cql/temp_identity.cql create mode 100644 auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/AbsCassDAO.java create mode 100644 auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/Bytification.java create mode 100644 auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/CIDAO.java create mode 100644 auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/Cacheable.java create mode 100644 auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/Cached.java create mode 100644 auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/CachedDAO.java create mode 100644 auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/CassAccess.java create mode 100644 auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/CassDAOImpl.java create mode 100644 auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/DAO.java create mode 100644 auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/DAOException.java create mode 100644 auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/DAO_RO.java create mode 100644 auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/Loader.java create mode 100644 auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/Streamer.java create mode 100644 auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/Touchable.java create mode 100644 auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/cached/CachedCertDAO.java create mode 100644 auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/cached/CachedCredDAO.java create mode 100644 auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/cached/CachedNSDAO.java create mode 100644 auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/cached/CachedPermDAO.java create mode 100644 auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/cached/CachedRoleDAO.java create mode 100644 auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/cached/CachedUserRoleDAO.java create mode 100644 auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/cass/.gitignore create mode 100644 auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/cass/ApprovalDAO.java create mode 100644 auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/cass/ArtiDAO.java create mode 100644 auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/cass/CacheInfoDAO.java create mode 100644 auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/cass/CacheableData.java create mode 100644 auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/cass/CertDAO.java create mode 100644 auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/cass/CredDAO.java create mode 100644 auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/cass/DelegateDAO.java create mode 100644 auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/cass/FutureDAO.java create mode 100644 auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/cass/HistoryDAO.java create mode 100644 auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/cass/LocateDAO.java create mode 100644 auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/cass/Namespace.java create mode 100644 auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/cass/NsDAO.java create mode 100644 auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/cass/NsSplit.java create mode 100644 auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/cass/NsType.java create mode 100644 auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/cass/OAuthTokenDAO.java create mode 100644 auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/cass/PermDAO.java create mode 100644 auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/cass/RoleDAO.java create mode 100644 auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/cass/Status.java create mode 100644 auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/cass/UserRoleDAO.java create mode 100644 auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/hl/CassExecutor.java create mode 100644 auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/hl/Function.java create mode 100644 auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/hl/PermLookup.java create mode 100644 auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/hl/Question.java create mode 100644 auth/auth-cass/src/main/java/org/onap/aaf/auth/direct/DirectAAFLocator.java create mode 100644 auth/auth-cass/src/main/java/org/onap/aaf/auth/direct/DirectAAFLur.java create mode 100644 auth/auth-cass/src/main/java/org/onap/aaf/auth/direct/DirectAAFUserPass.java create mode 100644 auth/auth-cass/src/main/java/org/onap/aaf/auth/direct/DirectCertIdentity.java create mode 100644 auth/auth-cass/src/main/java/org/onap/aaf/auth/direct/DirectLocatorCreator.java create mode 100644 auth/auth-cass/src/main/java/org/onap/aaf/auth/direct/DirectRegistrar.java create mode 100644 auth/auth-cass/src/test/java/com/att/dao/aaf/test/.gitignore create mode 100644 auth/auth-cass/src/test/java/com/att/dao/aaf/test/AbsJUCass.java create mode 100644 auth/auth-cass/src/test/java/com/att/dao/aaf/test/JU_ApprovalDAO.java create mode 100644 auth/auth-cass/src/test/java/com/att/dao/aaf/test/JU_ArtiDAO.java create mode 100644 auth/auth-cass/src/test/java/com/att/dao/aaf/test/JU_Bytification.java create mode 100644 auth/auth-cass/src/test/java/com/att/dao/aaf/test/JU_CacheInfoDAO.java create mode 100644 auth/auth-cass/src/test/java/com/att/dao/aaf/test/JU_CertDAO.java create mode 100644 auth/auth-cass/src/test/java/com/att/dao/aaf/test/JU_CredDAO.java create mode 100644 auth/auth-cass/src/test/java/com/att/dao/aaf/test/JU_DelegateDAO.java create mode 100644 auth/auth-cass/src/test/java/com/att/dao/aaf/test/JU_FastCalling.java create mode 100644 auth/auth-cass/src/test/java/com/att/dao/aaf/test/JU_HistoryDAO.java create mode 100644 auth/auth-cass/src/test/java/com/att/dao/aaf/test/JU_LocateDAO.java create mode 100644 auth/auth-cass/src/test/java/com/att/dao/aaf/test/JU_LocationContent.java create mode 100644 auth/auth-cass/src/test/java/com/att/dao/aaf/test/JU_NsDAO.java create mode 100644 auth/auth-cass/src/test/java/com/att/dao/aaf/test/JU_NsType.java create mode 100644 auth/auth-cass/src/test/java/com/att/dao/aaf/test/JU_OAuthTokenDAO.java create mode 100644 auth/auth-cass/src/test/java/com/att/dao/aaf/test/JU_PermDAO.java create mode 100644 auth/auth-cass/src/test/java/com/att/dao/aaf/test/JU_RoleDAO.java create mode 100644 auth/auth-cass/src/test/java/com/att/dao/aaf/test/NS_ChildUpdate.java create mode 100644 auth/auth-cass/src/test/java/org/onap/aaf/auth/cass/hl/JU_Question.java create mode 100644 auth/auth-cass/src/test/java/org/onap/aaf/auth/cass/hl/JU_Question2.java create mode 100644 auth/auth-cass/src/test/java/org/onap/aaf/auth/dao/JU_Cached.java create mode 100644 auth/auth-cass/src/test/java/org/onap/aaf/auth/dao/JU_CachedDAO.java create mode 100644 auth/auth-cass/src/test/java/org/onap/aaf/auth/dao/JU_CassAccess.java create mode 100644 auth/auth-cass/src/test/java/org/onap/aaf/auth/dao/JU_CassDAOImpl.java create mode 100644 auth/auth-cass/src/test/java/org/onap/aaf/auth/dao/JU_DAOException.java create mode 100644 auth/auth-cass/src/test/java/org/onap/aaf/auth/dao/aaf/test/AbsJUCass.java create mode 100644 auth/auth-cass/src/test/java/org/onap/aaf/auth/dao/aaf/test/JU_ApprovalDAO.java create mode 100644 auth/auth-cass/src/test/java/org/onap/aaf/auth/dao/aaf/test/JU_ArtiDAO.java create mode 100644 auth/auth-cass/src/test/java/org/onap/aaf/auth/dao/aaf/test/JU_Bytification.java create mode 100644 auth/auth-cass/src/test/java/org/onap/aaf/auth/dao/aaf/test/JU_CacheInfoDAO.java create mode 100644 auth/auth-cass/src/test/java/org/onap/aaf/auth/dao/aaf/test/JU_CertDAO.java create mode 100644 auth/auth-cass/src/test/java/org/onap/aaf/auth/dao/aaf/test/JU_CredDAO.java create mode 100644 auth/auth-cass/src/test/java/org/onap/aaf/auth/dao/aaf/test/JU_DelegateDAO.java create mode 100644 auth/auth-cass/src/test/java/org/onap/aaf/auth/dao/aaf/test/JU_FastCalling.java create mode 100644 auth/auth-cass/src/test/java/org/onap/aaf/auth/dao/aaf/test/JU_HistoryDAO.java create mode 100644 auth/auth-cass/src/test/java/org/onap/aaf/auth/dao/aaf/test/JU_NsDAO.java create mode 100644 auth/auth-cass/src/test/java/org/onap/aaf/auth/dao/aaf/test/JU_NsType.java create mode 100644 auth/auth-cass/src/test/java/org/onap/aaf/auth/dao/aaf/test/JU_PermDAO.java create mode 100644 auth/auth-cass/src/test/java/org/onap/aaf/auth/dao/aaf/test/JU_RoleDAO.java create mode 100644 auth/auth-cass/src/test/java/org/onap/aaf/auth/direct/test/JU_DirectAAFLur.java create mode 100644 auth/auth-cass/src/test/java/org/onap/aaf/auth/direct/test/JU_DirectAAFUserPass.java create mode 100644 auth/auth-cass/src/test/java/org/onap/aaf/auth/direct/test/JU_DirectCertIdentity.java create mode 100644 auth/auth-certman/.gitignore create mode 100644 auth/auth-certman/pom.xml create mode 100644 auth/auth-certman/src/main/config/.gitignore create mode 100644 auth/auth-certman/src/main/config/certman.props create mode 100644 auth/auth-certman/src/main/java/org/onap/aaf/auth/cm/AAF_CM.java create mode 100644 auth/auth-certman/src/main/java/org/onap/aaf/auth/cm/api/API_Artifact.java create mode 100644 auth/auth-certman/src/main/java/org/onap/aaf/auth/cm/api/API_Cert.java create mode 100644 auth/auth-certman/src/main/java/org/onap/aaf/auth/cm/ca/CA.java create mode 100644 auth/auth-certman/src/main/java/org/onap/aaf/auth/cm/ca/JscepCA.java create mode 100644 auth/auth-certman/src/main/java/org/onap/aaf/auth/cm/ca/LocalCA.java create mode 100644 auth/auth-certman/src/main/java/org/onap/aaf/auth/cm/ca/X509ChainWithIssuer.java create mode 100644 auth/auth-certman/src/main/java/org/onap/aaf/auth/cm/ca/X509andChain.java create mode 100644 auth/auth-certman/src/main/java/org/onap/aaf/auth/cm/cert/BCFactory.java create mode 100644 auth/auth-certman/src/main/java/org/onap/aaf/auth/cm/cert/CSRMeta.java create mode 100644 auth/auth-certman/src/main/java/org/onap/aaf/auth/cm/cert/RDN.java create mode 100644 auth/auth-certman/src/main/java/org/onap/aaf/auth/cm/data/CertDrop.java create mode 100644 auth/auth-certman/src/main/java/org/onap/aaf/auth/cm/data/CertRenew.java create mode 100644 auth/auth-certman/src/main/java/org/onap/aaf/auth/cm/data/CertReq.java create mode 100644 auth/auth-certman/src/main/java/org/onap/aaf/auth/cm/data/CertResp.java create mode 100644 auth/auth-certman/src/main/java/org/onap/aaf/auth/cm/facade/Facade.java create mode 100644 auth/auth-certman/src/main/java/org/onap/aaf/auth/cm/facade/Facade1_0.java create mode 100644 auth/auth-certman/src/main/java/org/onap/aaf/auth/cm/facade/FacadeFactory.java create mode 100644 auth/auth-certman/src/main/java/org/onap/aaf/auth/cm/facade/FacadeImpl.java create mode 100644 auth/auth-certman/src/main/java/org/onap/aaf/auth/cm/mapper/Mapper.java create mode 100644 auth/auth-certman/src/main/java/org/onap/aaf/auth/cm/mapper/Mapper1_0.java create mode 100644 auth/auth-certman/src/main/java/org/onap/aaf/auth/cm/mapper/Mapper2_0.java create mode 100644 auth/auth-certman/src/main/java/org/onap/aaf/auth/cm/service/CMService.java create mode 100644 auth/auth-certman/src/main/java/org/onap/aaf/auth/cm/service/Code.java create mode 100644 auth/auth-certman/src/main/java/org/onap/aaf/auth/cm/validation/CertmanValidator.java create mode 100644 auth/auth-certman/src/test/.gitignore create mode 100644 auth/auth-certman/src/test/java/org/onap/aaf/auth/cm/api/JU_API_Artifact.java create mode 100644 auth/auth-certman/src/test/java/org/onap/aaf/auth/cm/api/JU_API_Cert.java create mode 100644 auth/auth-certman/src/test/java/org/onap/aaf/auth/cm/ca/JU_AppCA.java create mode 100644 auth/auth-certman/src/test/java/org/onap/aaf/auth/cm/ca/JU_DevlCA.java create mode 100644 auth/auth-certman/src/test/java/org/onap/aaf/auth/cm/cert/JU_BCFactory.java create mode 100644 auth/auth-certman/src/test/java/org/onap/aaf/auth/cm/cert/JU_CSRMeta.java create mode 100644 auth/auth-certman/src/test/java/org/onap/aaf/auth/cm/data/JU_CertReq.java create mode 100644 auth/auth-certman/src/test/java/org/onap/aaf/auth/cm/facade/JU_FacadeImpl.java create mode 100644 auth/auth-certman/src/test/java/org/onap/aaf/auth/cm/test/CertmanTest.java create mode 100644 auth/auth-certman/src/test/java/org/onap/aaf/auth/cm/test/JU_KeyMarshaling.java create mode 100644 auth/auth-certman/src/test/java/org/onap/aaf/auth/cm/test/JU_SignTest.java create mode 100644 auth/auth-client/.gitignore create mode 100644 auth/auth-client/pom.xml create mode 100644 auth/auth-client/src/main/xsd/aaf_2_0.xsd create mode 100644 auth/auth-client/src/main/xsd/aaf_oauth2.xsd create mode 100644 auth/auth-client/src/main/xsd/certman_1_0.xsd create mode 100644 auth/auth-client/src/main/xsd/certman_2_0.xsd create mode 100644 auth/auth-client/src/main/xsd/locate_1_0.xsd create mode 100644 auth/auth-cmd/.gitignore create mode 100644 auth/auth-cmd/pom.xml create mode 100644 auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/AAFcli.java create mode 100644 auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/BaseCmd.java create mode 100644 auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/Cmd.java create mode 100644 auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/DeprecatedCMD.java create mode 100644 auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/Help.java create mode 100644 auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/MessageException.java create mode 100644 auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/Param.java create mode 100644 auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/Version.java create mode 100644 auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/mgmt/Cache.java create mode 100644 auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/mgmt/Clear.java create mode 100644 auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/mgmt/Deny.java create mode 100644 auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/mgmt/Log.java create mode 100644 auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/mgmt/Mgmt.java create mode 100644 auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/mgmt/SessClear.java create mode 100644 auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/mgmt/Session.java create mode 100644 auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/ns/Admin.java create mode 100644 auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/ns/Attrib.java create mode 100644 auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/ns/Create.java create mode 100644 auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/ns/Delete.java create mode 100644 auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/ns/Describe.java create mode 100644 auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/ns/List.java create mode 100644 auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/ns/ListActivity.java create mode 100644 auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/ns/ListAdminResponsible.java create mode 100644 auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/ns/ListByName.java create mode 100644 auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/ns/ListChildren.java create mode 100644 auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/ns/ListNsKeysByAttrib.java create mode 100644 auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/ns/ListUsers.java create mode 100644 auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/ns/ListUsersContact.java create mode 100644 auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/ns/ListUsersInRole.java create mode 100644 auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/ns/ListUsersWithPerm.java create mode 100644 auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/ns/NS.java create mode 100644 auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/ns/Owner.java create mode 100644 auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/perm/Create.java create mode 100644 auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/perm/Delete.java create mode 100644 auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/perm/Describe.java create mode 100644 auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/perm/Grant.java create mode 100644 auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/perm/List.java create mode 100644 auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/perm/ListActivity.java create mode 100644 auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/perm/ListByNS.java create mode 100644 auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/perm/ListByName.java create mode 100644 auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/perm/ListByRole.java create mode 100644 auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/perm/ListByUser.java create mode 100644 auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/perm/Perm.java create mode 100644 auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/perm/Rename.java create mode 100644 auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/role/CreateDelete.java create mode 100644 auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/role/Describe.java create mode 100644 auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/role/List.java create mode 100644 auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/role/ListActivity.java create mode 100644 auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/role/ListByNS.java create mode 100644 auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/role/ListByNameOnly.java create mode 100644 auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/role/ListByPerm.java create mode 100644 auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/role/ListByRole.java create mode 100644 auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/role/ListByUser.java create mode 100644 auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/role/Role.java create mode 100644 auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/role/User.java create mode 100644 auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/user/Cred.java create mode 100644 auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/user/Delg.java create mode 100644 auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/user/List.java create mode 100644 auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/user/ListActivity.java create mode 100644 auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/user/ListApprovals.java create mode 100644 auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/user/ListDelegates.java create mode 100644 auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/user/ListForCreds.java create mode 100644 auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/user/ListForPermission.java create mode 100644 auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/user/ListForRoles.java create mode 100644 auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/user/Role.java create mode 100644 auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/user/User.java create mode 100644 auth/auth-cmd/src/test/java/org/onap/aaf/auth/cmd/test/JU_AAFCli.java create mode 100644 auth/auth-cmd/src/test/java/org/onap/aaf/auth/cmd/test/JU_BaseCmd.java create mode 100644 auth/auth-cmd/src/test/java/org/onap/aaf/auth/cmd/test/JU_BasicAuth.java create mode 100644 auth/auth-cmd/src/test/java/org/onap/aaf/auth/cmd/test/JU_Help.java create mode 100644 auth/auth-cmd/src/test/java/org/onap/aaf/auth/cmd/test/JU_Version.java create mode 100644 auth/auth-cmd/src/test/java/org/onap/aaf/auth/cmd/test/mgmt/JU_Clear.java create mode 100644 auth/auth-cmd/src/test/java/org/onap/aaf/auth/cmd/test/mgmt/JU_Log.java create mode 100644 auth/auth-cmd/src/test/java/org/onap/aaf/auth/cmd/test/mgmt/JU_SessClear.java create mode 100644 auth/auth-cmd/src/test/java/org/onap/aaf/auth/cmd/test/ns/JU_Admin.java create mode 100644 auth/auth-cmd/src/test/java/org/onap/aaf/auth/cmd/test/ns/JU_Attrib.java create mode 100644 auth/auth-cmd/src/test/java/org/onap/aaf/auth/cmd/test/ns/JU_Create.java create mode 100644 auth/auth-cmd/src/test/java/org/onap/aaf/auth/cmd/test/ns/JU_Delete.java create mode 100644 auth/auth-cmd/src/test/java/org/onap/aaf/auth/cmd/test/ns/JU_Describe.java create mode 100644 auth/auth-cmd/src/test/java/org/onap/aaf/auth/cmd/test/ns/JU_ListActivity.java create mode 100644 auth/auth-cmd/src/test/java/org/onap/aaf/auth/cmd/test/ns/JU_ListAdminResponsible.java create mode 100644 auth/auth-cmd/src/test/java/org/onap/aaf/auth/cmd/test/ns/JU_ListByName.java create mode 100644 auth/auth-cmd/src/test/java/org/onap/aaf/auth/cmd/test/ns/JU_ListChildren.java create mode 100644 auth/auth-cmd/src/test/java/org/onap/aaf/auth/cmd/test/ns/JU_ListNsKeysByAttrib.java create mode 100644 auth/auth-cmd/src/test/java/org/onap/aaf/auth/cmd/test/ns/JU_ListUsersInRole.java create mode 100644 auth/auth-cmd/src/test/java/org/onap/aaf/auth/cmd/test/ns/JU_ListUsersWithPerm.java create mode 100644 auth/auth-cmd/src/test/java/org/onap/aaf/auth/cmd/test/ns/JU_Responsible.java create mode 100644 auth/auth-cmd/src/test/java/org/onap/aaf/auth/cmd/test/perm/JU_Create.java create mode 100644 auth/auth-cmd/src/test/java/org/onap/aaf/auth/cmd/test/perm/JU_Delete.java create mode 100644 auth/auth-cmd/src/test/java/org/onap/aaf/auth/cmd/test/perm/JU_Describe.java create mode 100644 auth/auth-cmd/src/test/java/org/onap/aaf/auth/cmd/test/perm/JU_Grant.java create mode 100644 auth/auth-cmd/src/test/java/org/onap/aaf/auth/cmd/test/perm/JU_ListActivity.java create mode 100644 auth/auth-cmd/src/test/java/org/onap/aaf/auth/cmd/test/perm/JU_ListByNS.java create mode 100644 auth/auth-cmd/src/test/java/org/onap/aaf/auth/cmd/test/perm/JU_ListByName.java create mode 100644 auth/auth-cmd/src/test/java/org/onap/aaf/auth/cmd/test/perm/JU_ListByRole.java create mode 100644 auth/auth-cmd/src/test/java/org/onap/aaf/auth/cmd/test/perm/JU_ListByUser.java create mode 100644 auth/auth-cmd/src/test/java/org/onap/aaf/auth/cmd/test/perm/JU_Rename.java create mode 100644 auth/auth-cmd/src/test/java/org/onap/aaf/auth/cmd/test/role/JU_CreateDelete.java create mode 100644 auth/auth-cmd/src/test/java/org/onap/aaf/auth/cmd/test/role/JU_Describe.java create mode 100644 auth/auth-cmd/src/test/java/org/onap/aaf/auth/cmd/test/role/JU_ListActivity.java create mode 100644 auth/auth-cmd/src/test/java/org/onap/aaf/auth/cmd/test/role/JU_ListByNS.java create mode 100644 auth/auth-cmd/src/test/java/org/onap/aaf/auth/cmd/test/role/JU_ListByNameOnly.java create mode 100644 auth/auth-cmd/src/test/java/org/onap/aaf/auth/cmd/test/role/JU_ListByPerm.java create mode 100644 auth/auth-cmd/src/test/java/org/onap/aaf/auth/cmd/test/role/JU_ListByRole.java create mode 100644 auth/auth-cmd/src/test/java/org/onap/aaf/auth/cmd/test/role/JU_ListByUser.java create mode 100644 auth/auth-cmd/src/test/java/org/onap/aaf/auth/cmd/test/role/JU_User.java create mode 100644 auth/auth-cmd/src/test/java/org/onap/aaf/auth/cmd/test/user/JU_Cred.java create mode 100644 auth/auth-cmd/src/test/java/org/onap/aaf/auth/cmd/test/user/JU_Delg.java create mode 100644 auth/auth-cmd/src/test/java/org/onap/aaf/auth/cmd/test/user/JU_ListActivity.java create mode 100644 auth/auth-cmd/src/test/java/org/onap/aaf/auth/cmd/test/user/JU_ListApprovals.java create mode 100644 auth/auth-cmd/src/test/java/org/onap/aaf/auth/cmd/test/user/JU_ListDelegates.java create mode 100644 auth/auth-cmd/src/test/java/org/onap/aaf/auth/cmd/test/user/JU_ListForCreds.java create mode 100644 auth/auth-cmd/src/test/java/org/onap/aaf/auth/cmd/test/user/JU_ListForPermission.java create mode 100644 auth/auth-cmd/src/test/java/org/onap/aaf/auth/cmd/test/user/JU_ListForRoles.java create mode 100644 auth/auth-cmd/src/test/java/org/onap/aaf/auth/cmd/test/user/JU_Role.java create mode 100644 auth/auth-core/.gitignore create mode 100644 auth/auth-core/pom.xml create mode 100644 auth/auth-core/src/main/java/org/onap/aaf/auth/cache/Cache.java create mode 100644 auth/auth-core/src/main/java/org/onap/aaf/auth/common/Define.java create mode 100644 auth/auth-core/src/main/java/org/onap/aaf/auth/env/AuthzEnv.java create mode 100644 auth/auth-core/src/main/java/org/onap/aaf/auth/env/AuthzTrans.java create mode 100644 auth/auth-core/src/main/java/org/onap/aaf/auth/env/AuthzTransFilter.java create mode 100644 auth/auth-core/src/main/java/org/onap/aaf/auth/env/AuthzTransImpl.java create mode 100644 auth/auth-core/src/main/java/org/onap/aaf/auth/env/AuthzTransOnlyFilter.java create mode 100644 auth/auth-core/src/main/java/org/onap/aaf/auth/env/NullTrans.java create mode 100644 auth/auth-core/src/main/java/org/onap/aaf/auth/layer/DirectIntrospectImpl.java create mode 100644 auth/auth-core/src/main/java/org/onap/aaf/auth/layer/FacadeImpl.java create mode 100644 auth/auth-core/src/main/java/org/onap/aaf/auth/layer/Result.java create mode 100644 auth/auth-core/src/main/java/org/onap/aaf/auth/local/AbsData.java create mode 100644 auth/auth-core/src/main/java/org/onap/aaf/auth/local/DataFile.java create mode 100644 auth/auth-core/src/main/java/org/onap/aaf/auth/local/TextIndex.java create mode 100644 auth/auth-core/src/main/java/org/onap/aaf/auth/org/EmailWarnings.java create mode 100644 auth/auth-core/src/main/java/org/onap/aaf/auth/org/Executor.java create mode 100644 auth/auth-core/src/main/java/org/onap/aaf/auth/org/Organization.java create mode 100644 auth/auth-core/src/main/java/org/onap/aaf/auth/org/OrganizationException.java create mode 100644 auth/auth-core/src/main/java/org/onap/aaf/auth/org/OrganizationFactory.java create mode 100644 auth/auth-core/src/main/java/org/onap/aaf/auth/rserv/Acceptor.java create mode 100644 auth/auth-core/src/main/java/org/onap/aaf/auth/rserv/CachingFileAccess.java create mode 100644 auth/auth-core/src/main/java/org/onap/aaf/auth/rserv/CodeSetter.java create mode 100644 auth/auth-core/src/main/java/org/onap/aaf/auth/rserv/Content.java create mode 100644 auth/auth-core/src/main/java/org/onap/aaf/auth/rserv/HttpCode.java create mode 100644 auth/auth-core/src/main/java/org/onap/aaf/auth/rserv/HttpMethods.java create mode 100644 auth/auth-core/src/main/java/org/onap/aaf/auth/rserv/Match.java create mode 100644 auth/auth-core/src/main/java/org/onap/aaf/auth/rserv/Pair.java create mode 100644 auth/auth-core/src/main/java/org/onap/aaf/auth/rserv/RServlet.java create mode 100644 auth/auth-core/src/main/java/org/onap/aaf/auth/rserv/Route.java create mode 100644 auth/auth-core/src/main/java/org/onap/aaf/auth/rserv/RouteReport.java create mode 100644 auth/auth-core/src/main/java/org/onap/aaf/auth/rserv/Routes.java create mode 100644 auth/auth-core/src/main/java/org/onap/aaf/auth/rserv/TransFilter.java create mode 100644 auth/auth-core/src/main/java/org/onap/aaf/auth/rserv/TransOnlyFilter.java create mode 100644 auth/auth-core/src/main/java/org/onap/aaf/auth/rserv/TypedCode.java create mode 100644 auth/auth-core/src/main/java/org/onap/aaf/auth/rserv/Version.java create mode 100644 auth/auth-core/src/main/java/org/onap/aaf/auth/rserv/doc/ApiDoc.java create mode 100644 auth/auth-core/src/main/java/org/onap/aaf/auth/server/AbsService.java create mode 100644 auth/auth-core/src/main/java/org/onap/aaf/auth/server/AbsServiceStarter.java create mode 100644 auth/auth-core/src/main/java/org/onap/aaf/auth/server/JettyServiceStarter.java create mode 100644 auth/auth-core/src/main/java/org/onap/aaf/auth/server/ServiceStarter.java create mode 100644 auth/auth-core/src/main/java/org/onap/aaf/auth/validation/Validator.java create mode 100644 auth/auth-core/src/test/java/org/onap/aaf/auth/common/test/JU_Define.java create mode 100644 auth/auth-core/src/test/java/org/onap/aaf/auth/env/test/JU_AuthzEnv.java create mode 100644 auth/auth-core/src/test/java/org/onap/aaf/auth/env/test/JU_AuthzTransFilter.java create mode 100644 auth/auth-core/src/test/java/org/onap/aaf/auth/env/test/JU_AuthzTransImpl.java create mode 100644 auth/auth-core/src/test/java/org/onap/aaf/auth/env/test/JU_AuthzTransOnlyFilter.java create mode 100644 auth/auth-core/src/test/java/org/onap/aaf/auth/env/test/JU_NullTrans.java create mode 100644 auth/auth-core/src/test/java/org/onap/aaf/auth/layer/test/JU_Result.java create mode 100644 auth/auth-core/src/test/java/org/onap/aaf/auth/local/test/JU_DataFile.java create mode 100644 auth/auth-core/src/test/java/org/onap/aaf/auth/local/test/JU_TextIndex.java create mode 100644 auth/auth-core/src/test/java/org/onap/aaf/auth/org/test/JU_OrganizationException.java create mode 100644 auth/auth-core/src/test/java/org/onap/aaf/auth/org/test/JU_OrganizationFactory.java create mode 100644 auth/auth-core/src/test/java/org/onap/aaf/auth/request/test/CredCompare.java create mode 100644 auth/auth-core/src/test/java/org/onap/aaf/auth/request/test/JU_RequestCheck.java create mode 100644 auth/auth-core/src/test/java/org/onap/aaf/auth/request/test/MultiCompare.java create mode 100644 auth/auth-core/src/test/java/org/onap/aaf/auth/request/test/NSAttribCompare.java create mode 100644 auth/auth-core/src/test/java/org/onap/aaf/auth/request/test/NSCompare.java create mode 100644 auth/auth-core/src/test/java/org/onap/aaf/auth/request/test/PermCompare.java create mode 100644 auth/auth-core/src/test/java/org/onap/aaf/auth/request/test/RoleCompare.java create mode 100644 auth/auth-core/src/test/java/org/onap/aaf/auth/request/test/RolePermCompare.java create mode 100644 auth/auth-core/src/test/java/org/onap/aaf/auth/request/test/RosettaCompare.java create mode 100644 auth/auth-core/src/test/java/org/onap/aaf/auth/request/test/UserRoleCompare.java create mode 100644 auth/auth-core/src/test/java/org/onap/aaf/auth/rserv/test/JU_BetterMatch.java create mode 100644 auth/auth-core/src/test/java/org/onap/aaf/auth/rserv/test/JU_BetterMatch1.java create mode 100644 auth/auth-core/src/test/java/org/onap/aaf/auth/rserv/test/JU_BetterRoute.java create mode 100644 auth/auth-core/src/test/java/org/onap/aaf/auth/rserv/test/JU_CachingFileAccess.java create mode 100644 auth/auth-core/src/test/java/org/onap/aaf/auth/rserv/test/JU_CodeSetter.java create mode 100644 auth/auth-core/src/test/java/org/onap/aaf/auth/rserv/test/JU_Content.java create mode 100644 auth/auth-core/src/test/java/org/onap/aaf/auth/rserv/test/JU_Content1.java create mode 100644 auth/auth-core/src/test/java/org/onap/aaf/auth/rserv/test/JU_Pair.java create mode 100644 auth/auth-core/src/test/java/org/onap/aaf/auth/rserv/test/JU_Route.java create mode 100644 auth/auth-core/src/test/java/org/onap/aaf/auth/rserv/test/JU_RouteReport.java create mode 100644 auth/auth-core/src/test/java/org/onap/aaf/auth/rserv/test/JU_Routes.java create mode 100644 auth/auth-core/src/test/java/org/onap/aaf/auth/rserv/test/JU_TypedCode.java create mode 100644 auth/auth-core/src/test/java/org/onap/aaf/auth/rserv/test/JU_Version.java create mode 100644 auth/auth-core/src/test/java/org/onap/aaf/auth/server/test/JU_JettyServiceStarter.java create mode 100644 auth/auth-core/src/test/java/org/onap/aaf/auth/util/test/JU_Mask.java create mode 100644 auth/auth-core/src/test/java/org/onap/aaf/auth/validation/test/JU_Validator.java create mode 100644 auth/auth-core/test/sample.identities.dat create mode 100644 auth/auth-deforg/.gitignore create mode 100644 auth/auth-deforg/pom.xml create mode 100644 auth/auth-deforg/src/main/java/org/onap/aaf/org/DefaultOrg.java create mode 100644 auth/auth-deforg/src/main/java/org/onap/aaf/org/DefaultOrgIdentity.java create mode 100644 auth/auth-deforg/src/main/java/org/onap/aaf/org/DefaultOrgWarnings.java create mode 100644 auth/auth-deforg/src/main/java/org/onap/aaf/org/Identities.java create mode 100644 auth/auth-deforg/src/test/java/org/onap/aaf/org/test/JU_DefaultOrg.java create mode 100644 auth/auth-deforg/src/test/java/org/onap/aaf/org/test/JU_DefaultOrgIdentity.java create mode 100644 auth/auth-deforg/src/test/java/org/onap/aaf/org/test/JU_DefaultOrgWarnings.java create mode 100644 auth/auth-deforg/src/test/java/org/onap/aaf/org/test/JU_Identities.java create mode 100644 auth/auth-deforg/src/test/resources/test.txt create mode 100644 auth/auth-fs/.gitignore create mode 100644 auth/auth-fs/pom.xml create mode 100644 auth/auth-fs/src/main/config/.gitignore create mode 100644 auth/auth-fs/src/main/config/FileServer.props create mode 100644 auth/auth-fs/src/main/data/favicon.ico create mode 100644 auth/auth-fs/src/main/data/test.html create mode 100644 auth/auth-fs/src/main/java/org/onap/aaf/auth/fs/AAF_FS.java create mode 100644 auth/auth-fs/src/test/java/org/onap/aaf/auth/fs/test/JU_FileServer.java create mode 100644 auth/auth-gui/.gitignore create mode 100644 auth/auth-gui/pom.xml create mode 100644 auth/auth-gui/src/main/config/.gitignore create mode 100644 auth/auth-gui/src/main/java/org/onap/aaf/auth/cui/CUI.java create mode 100644 auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/AAF_GUI.java create mode 100644 auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/BreadCrumbs.java create mode 100644 auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/ContentCode.java create mode 100644 auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/Controls.java create mode 100644 auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/Display.java create mode 100644 auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/Form.java create mode 100644 auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/NamedCode.java create mode 100644 auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/OrgLookupFilter.java create mode 100644 auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/Page.java create mode 100644 auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/SlotCode.java create mode 100644 auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/Table.java create mode 100644 auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/XFrameFilter.java create mode 100644 auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/pages/ApiDocs.java create mode 100644 auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/pages/ApiExample.java create mode 100644 auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/pages/ApprovalAction.java create mode 100644 auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/pages/ApprovalForm.java create mode 100644 auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/pages/CMArtiChangeAction.java create mode 100644 auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/pages/CMArtiChangeForm.java create mode 100644 auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/pages/CMArtifactShow.java create mode 100644 auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/pages/CredDetail.java create mode 100644 auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/pages/Home.java create mode 100644 auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/pages/LoginLanding.java create mode 100644 auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/pages/LoginLandingAction.java create mode 100644 auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/pages/NsDetail.java create mode 100644 auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/pages/NsHistory.java create mode 100644 auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/pages/NsInfoAction.java create mode 100644 auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/pages/NsInfoForm.java create mode 100644 auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/pages/NssShow.java create mode 100644 auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/pages/PassChangeAction.java create mode 100644 auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/pages/PassChangeForm.java create mode 100644 auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/pages/PassDeleteAction.java create mode 100644 auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/pages/PendingRequestsShow.java create mode 100644 auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/pages/PermDetail.java create mode 100644 auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/pages/PermGrantAction.java create mode 100644 auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/pages/PermGrantForm.java create mode 100644 auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/pages/PermHistory.java create mode 100644 auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/pages/PermsShow.java create mode 100644 auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/pages/RequestDetail.java create mode 100644 auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/pages/RoleDetail.java create mode 100644 auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/pages/RoleDetailAction.java create mode 100644 auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/pages/RoleHistory.java create mode 100644 auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/pages/RolesShow.java create mode 100644 auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/pages/UserRoleExtend.java create mode 100644 auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/pages/UserRoleRemove.java create mode 100644 auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/pages/WebCommand.java create mode 100644 auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/table/AbsCell.java create mode 100644 auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/table/ButtonCell.java create mode 100644 auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/table/CheckBoxCell.java create mode 100644 auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/table/RadioCell.java create mode 100644 auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/table/RefCell.java create mode 100644 auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/table/TableData.java create mode 100644 auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/table/TextAndRefCell.java create mode 100644 auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/table/TextCell.java create mode 100644 auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/table/TextInputCell.java create mode 100644 auth/auth-gui/theme/onap/AAF_details.png create mode 100644 auth/auth-gui/theme/onap/AAF_font_size.png create mode 100644 auth/auth-gui/theme/onap/AAF_maximize.png create mode 100644 auth/auth-gui/theme/onap/AAFdownload.png create mode 100644 auth/auth-gui/theme/onap/AAFemail.png create mode 100644 auth/auth-gui/theme/onap/LF_Collab_footer_gray.png create mode 100644 auth/auth-gui/theme/onap/LF_Collab_footer_gray_stripe.png create mode 100644 auth/auth-gui/theme/onap/LF_Collab_header_gray.png create mode 100644 auth/auth-gui/theme/onap/ONAP_LOGO.png create mode 100644 auth/auth-gui/theme/onap/aaf5.css create mode 100644 auth/auth-gui/theme/onap/aaf5Desktop.css create mode 100644 auth/auth-gui/theme/onap/aaf5iPhone.css create mode 100644 auth/auth-gui/theme/onap/comm.js create mode 100644 auth/auth-gui/theme/onap/common.js create mode 100644 auth/auth-gui/theme/onap/console.js create mode 100644 auth/auth-gui/theme/onap/favicon.ico create mode 100644 auth/auth-gui/theme/onap/logo_onap.png create mode 100644 auth/auth-gui/theme/onap/options_down.png create mode 100644 auth/auth-gui/theme/onap/options_up.png create mode 100644 auth/auth-hello/.gitignore create mode 100644 auth/auth-hello/pom.xml create mode 100644 auth/auth-hello/src/main/config/.gitignore create mode 100644 auth/auth-hello/src/main/config/hello.props create mode 100644 auth/auth-hello/src/main/java/org/onap/aaf/auth/hello/AAF_Hello.java create mode 100644 auth/auth-hello/src/main/java/org/onap/aaf/auth/hello/API_Hello.java create mode 100644 auth/auth-hello/src/test/java/org/onap/aaf/auth/hello/test/HelloTester.java create mode 100644 auth/auth-locate/.gitignore create mode 100644 auth/auth-locate/pom.xml create mode 100644 auth/auth-locate/src/main/.gitignore create mode 100644 auth/auth-locate/src/main/config/.gitignore create mode 100644 auth/auth-locate/src/main/java/org/onap/aaf/auth/locate/AAF_Locate.java create mode 100644 auth/auth-locate/src/main/java/org/onap/aaf/auth/locate/BasicAuthCode.java create mode 100644 auth/auth-locate/src/main/java/org/onap/aaf/auth/locate/LocateCode.java create mode 100644 auth/auth-locate/src/main/java/org/onap/aaf/auth/locate/api/API_AAFAccess.java create mode 100644 auth/auth-locate/src/main/java/org/onap/aaf/auth/locate/api/API_Api.java create mode 100644 auth/auth-locate/src/main/java/org/onap/aaf/auth/locate/api/API_Find.java create mode 100644 auth/auth-locate/src/main/java/org/onap/aaf/auth/locate/api/API_Proxy.java create mode 100644 auth/auth-locate/src/main/java/org/onap/aaf/auth/locate/facade/LocateFacade.java create mode 100644 auth/auth-locate/src/main/java/org/onap/aaf/auth/locate/facade/LocateFacadeFactory.java create mode 100644 auth/auth-locate/src/main/java/org/onap/aaf/auth/locate/facade/LocateFacadeImpl.java create mode 100644 auth/auth-locate/src/main/java/org/onap/aaf/auth/locate/facade/LocateFacade_1_0.java create mode 100644 auth/auth-locate/src/main/java/org/onap/aaf/auth/locate/mapper/Mapper.java create mode 100644 auth/auth-locate/src/main/java/org/onap/aaf/auth/locate/mapper/Mapper_1_0.java create mode 100644 auth/auth-locate/src/main/java/org/onap/aaf/auth/locate/service/LocateService.java create mode 100644 auth/auth-locate/src/main/java/org/onap/aaf/auth/locate/service/LocateServiceImpl.java create mode 100644 auth/auth-locate/src/main/java/org/onap/aaf/auth/locate/validation/LocateValidator.java create mode 100644 auth/auth-locate/src/main/xsd/locate_1_0.xsd create mode 100644 auth/auth-oauth/.gitignore create mode 100644 auth/auth-oauth/pom.xml create mode 100644 auth/auth-oauth/src/main/config/.gitignore create mode 100644 auth/auth-oauth/src/main/config/oauth.props create mode 100644 auth/auth-oauth/src/main/java/org/onap/aaf/auth/oauth/AAF_OAuth.java create mode 100644 auth/auth-oauth/src/main/java/org/onap/aaf/auth/oauth/DirectOAuthTAF.java create mode 100644 auth/auth-oauth/src/main/java/org/onap/aaf/auth/oauth/OACode.java create mode 100644 auth/auth-oauth/src/main/java/org/onap/aaf/auth/oauth/OAuth2Filter.java create mode 100644 auth/auth-oauth/src/main/java/org/onap/aaf/auth/oauth/OAuth2FormHttpTafResp.java create mode 100644 auth/auth-oauth/src/main/java/org/onap/aaf/auth/oauth/api/API_Token.java create mode 100644 auth/auth-oauth/src/main/java/org/onap/aaf/auth/oauth/facade/DirectIntrospect.java create mode 100644 auth/auth-oauth/src/main/java/org/onap/aaf/auth/oauth/facade/DirectIntrospectImpl.java create mode 100644 auth/auth-oauth/src/main/java/org/onap/aaf/auth/oauth/facade/DirectOAFacadeImpl.java create mode 100644 auth/auth-oauth/src/main/java/org/onap/aaf/auth/oauth/facade/OAFacade.java create mode 100644 auth/auth-oauth/src/main/java/org/onap/aaf/auth/oauth/facade/OAFacade1_0.java create mode 100644 auth/auth-oauth/src/main/java/org/onap/aaf/auth/oauth/facade/OAFacadeFactory.java create mode 100644 auth/auth-oauth/src/main/java/org/onap/aaf/auth/oauth/facade/OAFacadeImpl.java create mode 100644 auth/auth-oauth/src/main/java/org/onap/aaf/auth/oauth/mapper/Mapper.java create mode 100644 auth/auth-oauth/src/main/java/org/onap/aaf/auth/oauth/mapper/Mapper1_0.java create mode 100644 auth/auth-oauth/src/main/java/org/onap/aaf/auth/oauth/mapper/MapperIntrospect.java create mode 100644 auth/auth-oauth/src/main/java/org/onap/aaf/auth/oauth/mapper/MapperIntrospect1_0.java create mode 100644 auth/auth-oauth/src/main/java/org/onap/aaf/auth/oauth/service/JSONPermLoader.java create mode 100644 auth/auth-oauth/src/main/java/org/onap/aaf/auth/oauth/service/JSONPermLoaderFactory.java create mode 100644 auth/auth-oauth/src/main/java/org/onap/aaf/auth/oauth/service/OAuthService.java create mode 100644 auth/auth-oauth/src/main/java/org/onap/aaf/auth/oauth/service/OCreds.java create mode 100644 auth/auth-service/.gitignore create mode 100644 auth/auth-service/pom.xml create mode 100644 auth/auth-service/src/main/config/.gitignore create mode 100644 auth/auth-service/src/main/docker/.gitignore create mode 100644 auth/auth-service/src/main/java/org/onap/aaf/auth/service/AAF_Service.java create mode 100644 auth/auth-service/src/main/java/org/onap/aaf/auth/service/AuthzCassServiceImpl.java create mode 100644 auth/auth-service/src/main/java/org/onap/aaf/auth/service/AuthzService.java create mode 100644 auth/auth-service/src/main/java/org/onap/aaf/auth/service/Code.java create mode 100644 auth/auth-service/src/main/java/org/onap/aaf/auth/service/MayChange.java create mode 100644 auth/auth-service/src/main/java/org/onap/aaf/auth/service/api/API_Api.java create mode 100644 auth/auth-service/src/main/java/org/onap/aaf/auth/service/api/API_Approval.java create mode 100644 auth/auth-service/src/main/java/org/onap/aaf/auth/service/api/API_Creds.java create mode 100644 auth/auth-service/src/main/java/org/onap/aaf/auth/service/api/API_Delegate.java create mode 100644 auth/auth-service/src/main/java/org/onap/aaf/auth/service/api/API_History.java create mode 100644 auth/auth-service/src/main/java/org/onap/aaf/auth/service/api/API_Mgmt.java create mode 100644 auth/auth-service/src/main/java/org/onap/aaf/auth/service/api/API_Multi.java create mode 100644 auth/auth-service/src/main/java/org/onap/aaf/auth/service/api/API_NS.java create mode 100644 auth/auth-service/src/main/java/org/onap/aaf/auth/service/api/API_Perms.java create mode 100644 auth/auth-service/src/main/java/org/onap/aaf/auth/service/api/API_Roles.java create mode 100644 auth/auth-service/src/main/java/org/onap/aaf/auth/service/api/API_User.java create mode 100644 auth/auth-service/src/main/java/org/onap/aaf/auth/service/api/API_UserRole.java create mode 100644 auth/auth-service/src/main/java/org/onap/aaf/auth/service/facade/AuthzFacade.java create mode 100644 auth/auth-service/src/main/java/org/onap/aaf/auth/service/facade/AuthzFacadeFactory.java create mode 100644 auth/auth-service/src/main/java/org/onap/aaf/auth/service/facade/AuthzFacadeImpl.java create mode 100644 auth/auth-service/src/main/java/org/onap/aaf/auth/service/facade/AuthzFacade_2_0.java create mode 100644 auth/auth-service/src/main/java/org/onap/aaf/auth/service/mapper/Mapper.java create mode 100644 auth/auth-service/src/main/java/org/onap/aaf/auth/service/mapper/Mapper_2_0.java create mode 100644 auth/auth-service/src/main/java/org/onap/aaf/auth/service/validation/ServiceValidator.java create mode 100644 auth/auth-service/src/main/resources/docker-compose/.gitignore create mode 100644 auth/auth-service/src/main/resources/docker-compose/data/.gitignore create mode 100644 auth/auth-service/src/main/resources/docker-compose/data/ecomp.cql create mode 100644 auth/auth-service/src/main/resources/docker-compose/data/init.cql create mode 100644 auth/auth-service/src/main/resources/docker-compose/data2/.gitignore create mode 100644 auth/auth-service/src/main/resources/docker-compose/wait_for_host_port.sh create mode 100644 auth/auth-service/src/main/resources/docker/.gitignore create mode 100644 auth/auth-service/src/main/resources/etc/.gitignore create mode 100644 auth/auth-service/src/test/java/org/onap/aaf/auth/service/api/test/.gitignore create mode 100644 auth/auth-service/src/test/java/org/onap/aaf/auth/service/api/test/JU_API_Approval.java create mode 100644 auth/auth-service/src/test/java/org/onap/aaf/auth/service/api/test/JU_API_Creds.java create mode 100644 auth/auth-service/src/test/java/org/onap/aaf/auth/service/api/test/JU_API_Delegate.java create mode 100644 auth/auth-service/src/test/java/org/onap/aaf/auth/service/api/test/JU_API_History.java create mode 100644 auth/auth-service/src/test/java/org/onap/aaf/auth/service/api/test/JU_API_Mgmt.java create mode 100644 auth/auth-service/src/test/java/org/onap/aaf/auth/service/api/test/JU_API_NS.java create mode 100644 auth/auth-service/src/test/java/org/onap/aaf/auth/service/api/test/JU_API_Perms.java create mode 100644 auth/auth-service/src/test/java/org/onap/aaf/auth/service/api/test/JU_API_Roles.java create mode 100644 auth/auth-service/src/test/java/org/onap/aaf/auth/service/api/test/JU_API_User.java create mode 100644 auth/auth-service/src/test/java/org/onap/aaf/auth/service/api/test/JU_API_UserRole.java create mode 100644 auth/auth-service/src/test/java/org/onap/aaf/auth/service/validation/test/JU_ServiceValidator.java create mode 100644 auth/auth-service/src/test/java/org/onap/aaf/authz/service/mapper/JU_Mapper_2_0.java create mode 100644 auth/docker/Dockerfile create mode 100644 auth/docker/dbash create mode 100644 auth/docker/dbuild create mode 100644 auth/docker/drun create mode 100644 auth/pom.xml diff --git a/auth/.gitignore b/auth/.gitignore new file mode 100644 index 00000000..a2ac34ab --- /dev/null +++ b/auth/.gitignore @@ -0,0 +1,12 @@ +/target +/.settings +/dme2reg +/src +/.classpath +/logs +/bin/ +/temp +/.project +/assembly/ +/aaf_2.*/ +/aaf_2.1.0-SNAPSHOT.zip diff --git a/auth/auth-batch/.gitignore b/auth/auth-batch/.gitignore new file mode 100644 index 00000000..7743b8df --- /dev/null +++ b/auth/auth-batch/.gitignore @@ -0,0 +1,9 @@ +/logs +/target +/.classpath +/.settings +/sync +/data/ +/lib/ +/bin/ +/.project diff --git a/auth/auth-batch/pom.xml b/auth/auth-batch/pom.xml new file mode 100644 index 00000000..8aabdf54 --- /dev/null +++ b/auth/auth-batch/pom.xml @@ -0,0 +1,129 @@ + + + + 4.0.0 + + org.onap.aaf.auth + parent + 2.1.0-SNAPSHOT + ../pom.xml + + + auth-batch + AAF Auth Batch + Batch Processing for AAF Auth + jar + + + + Jonathan Gathman + jonathan.gathman@att.com + ATT + + Architect + Lead Developer + + + + Gabe Maurer + gabe.maurer@att.com + ATT + + Developer + + + + Ian Howell + ian.howell@att.com + ATT + + Developer + + + + + + false + + + + + + org.onap.aaf.misc + aaf-misc-env + + + + org.onap.aaf.cadi + aaf-cadi-core + + + + org.onap.aaf.misc + aaf-misc-rosetta + + + + org.onap.aaf.cadi + aaf-cadi-aaf + + + + org.onap.aaf.auth + aaf-auth-cass + + + + org.joda + joda-time + 2.5 + + + + org.slf4j + slf4j-log4j12 + + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + + 1.7 + 1.7 + + + + + org.apache.maven.plugins + maven-deploy-plugin + + true + + + + + diff --git a/auth/auth-batch/src/main/config/.gitignore b/auth/auth-batch/src/main/config/.gitignore new file mode 100644 index 00000000..28a74e22 --- /dev/null +++ b/auth/auth-batch/src/main/config/.gitignore @@ -0,0 +1,2 @@ +/authBatch.props +/log4j.properties diff --git a/auth/auth-batch/src/main/java/org/onap/aaf/auth/Batch.java b/auth/auth-batch/src/main/java/org/onap/aaf/auth/Batch.java new file mode 100644 index 00000000..6d9252e2 --- /dev/null +++ b/auth/auth-batch/src/main/java/org/onap/aaf/auth/Batch.java @@ -0,0 +1,524 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.PrintStream; +import java.lang.reflect.Constructor; +import java.net.InetAddress; +import java.net.URL; +import java.net.UnknownHostException; +import java.nio.ByteBuffer; +import java.text.SimpleDateFormat; +import java.util.GregorianCalendar; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.TimeZone; + +import org.apache.log4j.Logger; +import org.onap.aaf.auth.common.Define; +import org.onap.aaf.auth.dao.CassAccess; +import org.onap.aaf.auth.dao.cass.RoleDAO; +import org.onap.aaf.auth.dao.cass.UserRoleDAO; +import org.onap.aaf.auth.dao.hl.Question; +import org.onap.aaf.auth.env.AuthzEnv; +import org.onap.aaf.auth.env.AuthzTrans; +import org.onap.aaf.auth.layer.Result; +import org.onap.aaf.auth.org.Organization; +import org.onap.aaf.auth.org.OrganizationException; +import org.onap.aaf.auth.org.OrganizationFactory; +import org.onap.aaf.auth.org.Organization.Identity; +import org.onap.aaf.cadi.PropAccess; +import org.onap.aaf.misc.env.APIException; +import org.onap.aaf.misc.env.Env; +import org.onap.aaf.misc.env.StaticSlot; +import org.onap.aaf.misc.env.TimeTaken; +import org.onap.aaf.misc.env.impl.Log4JLogTarget; +import org.onap.aaf.misc.env.log4j.LogFileNamer; + +import com.datastax.driver.core.Cluster; +import com.datastax.driver.core.ResultSet; +import com.datastax.driver.core.Row; +import com.datastax.driver.core.Session; +import com.datastax.driver.core.Statement; + +public abstract class Batch { + + private static String ROOT_NS; + + private static StaticSlot ssargs; + + protected static final String STARS = "*****"; + + protected final Cluster cluster; + protected static AuthzEnv env; + protected static Session session; + protected static Logger aspr; + protected static Set specialNames; + protected static boolean dryRun; + protected static String batchEnv; + + public static final String CASS_ENV = "CASS_ENV"; + public static final String LOG_DIR = "LOG_DIR"; + protected final static String PUNT="punt"; + protected final static String MAX_EMAILS="MAX_EMAILS"; + protected final static String VERSION="VERSION"; + public final static String GUI_URL="GUI_URL"; + + protected final static String ORA_URL="ora_url"; + protected final static String ORA_PASSWORD="ora_password"; + protected final Organization org; + + + + protected Batch(AuthzEnv env) throws APIException, IOException, OrganizationException { + // Be able to change Environments + // load extra properties, i.e. + // PERF.cassandra.clusters=.... + batchEnv = env.getProperty(CASS_ENV); + if(batchEnv != null) { + batchEnv = batchEnv.trim(); + env.info().log("Redirecting to ",batchEnv,"environment"); + String str; + for(String key : new String[]{ + CassAccess.CASSANDRA_CLUSTERS, + CassAccess.CASSANDRA_CLUSTERS_PORT, + CassAccess.CASSANDRA_CLUSTERS_USER_NAME, + CassAccess.CASSANDRA_CLUSTERS_PASSWORD, + VERSION,GUI_URL,PUNT,MAX_EMAILS, + LOG_DIR, + "SPECIAL_NAMES" + }) { + if((str = env.getProperty(batchEnv+'.'+key))!=null) { + env.setProperty(key, str); + } + } + } + + // Setup for Dry Run + cluster = CassAccess.cluster(env,batchEnv); + env.info().log("cluster name - ",cluster.getClusterName()); + String dryRunStr = env.getProperty( "DRY_RUN" ); + if ( dryRunStr == null || dryRunStr.trim().equals("false") ) { + dryRun = false; + } else { + dryRun = true; + env.info().log("dryRun set to TRUE"); + } + + org = OrganizationFactory.init(env); + org.setTestMode(dryRun); + + // Special names to allow behaviors beyond normal rules + specialNames = new HashSet(); + String names = env.getProperty( "SPECIAL_NAMES" ); + if ( names != null ) + { + env.info().log("Loading SPECIAL_NAMES"); + for (String s :names.split(",") ) + { + env.info().log("\tspecial: " + s ); + specialNames.add( s.trim() ); + } + } + } + + protected abstract void run(AuthzTrans trans); + protected abstract void _close(AuthzTrans trans); + + public String[] args() { + return (String[])env.get(ssargs); + } + + public boolean isDryRun() + { + return dryRun; + } + + public boolean isSpecial(String user) { + if (specialNames != null && specialNames.contains(user)) { + env.info().log("specialName: " + user); + + return (true); + } else { + return (false); + } + } + + public boolean isMechID(String user) { + if (user.matches("m[0-9][0-9][0-9][0-9][0-9]")) { + return (true); + } else { + return (false); + } + } + + protected PrintStream fallout(PrintStream _fallout, String logType) + throws IOException { + PrintStream fallout = _fallout; + if (fallout == null) { + File dir = new File("logs"); + if (!dir.exists()) { + dir.mkdirs(); + } + + File f = null; + // String os = System.getProperty("os.name").toLowerCase(); + long uniq = System.currentTimeMillis(); + + f = new File(dir, getClass().getSimpleName() + "_" + logType + "_" + + uniq + ".log"); + + fallout = new PrintStream(new FileOutputStream(f, true)); + } + return fallout; + } + + public Organization getOrgFromID(AuthzTrans trans, String user) { + Organization org; + try { + org = OrganizationFactory.obtain(trans.env(),user.toLowerCase()); + } catch (OrganizationException e1) { + trans.error().log(e1); + org=null; + } + + if (org == null) { + PrintStream fallout = null; + + try { + fallout = fallout(fallout, "Fallout"); + fallout.print("INVALID_ID,"); + fallout.println(user); + } catch (Exception e) { + env.error().log("Could not write to Fallout File", e); + } + return (null); + } + + return (org); + } + + public static Row executeDeleteQuery(Statement stmt) { + Row row = null; + if (!dryRun) { + row = session.execute(stmt).one(); + } + + return (row); + + } + + public static int acquireRunLock(String className) { + Boolean testEnv = true; + String envStr = env.getProperty("AFT_ENVIRONMENT"); + + if (envStr != null) { + if (envStr.equals("AFTPRD")) { + testEnv = false; + } + } else { + env.fatal() + .log("AFT_ENVIRONMENT property is required and was not found. Exiting."); + System.exit(1); + } + + if (testEnv) { + env.info().log("TESTMODE: skipping RunLock"); + return (1); + } + + String hostname = null; + try { + hostname = InetAddress.getLocalHost().getHostName(); + } catch (UnknownHostException e) { + e.printStackTrace(); + env.warn().log("Unable to get hostname"); + return (0); + } + + ResultSet existing = session.execute(String.format( + "select * from authz.run_lock where class = '%s'", className)); + + for (Row row : existing) { + long curr = System.currentTimeMillis(); + ByteBuffer lastRun = row.getBytesUnsafe(2); // Can I get this field + // by name? + + long interval = (1 * 60 * 1000); // @@ Create a value in props file + // for this + long prev = lastRun.getLong(); + + if ((curr - prev) <= interval) { + env.warn().log( + String.format("Too soon! Last run was %d minutes ago.", + ((curr - prev) / 1000) / 60)); + env.warn().log( + String.format("Min time between runs is %d minutes ", + (interval / 1000) / 60)); + env.warn().log( + String.format("Last ran on machine: %s at %s", + row.getString("host"), row.getDate("start"))); + return (0); + } else { + env.info().log("Delete old lock"); + deleteLock(className); + } + } + + GregorianCalendar current = new GregorianCalendar(); + + // We want our time in UTC, hence "+0000" + SimpleDateFormat fmt = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss+0000"); + fmt.setTimeZone(TimeZone.getTimeZone("UTC")); + + String cql = String + .format("INSERT INTO authz.run_lock (class,host,start) VALUES ('%s','%s','%s') IF NOT EXISTS", + className, hostname, fmt.format(current.getTime())); + + env.info().log(cql); + + Row row = session.execute(cql).one(); + if (!row.getBool("[applied]")) { + env.warn().log("Lightweight Transaction failed to write lock."); + env.warn().log( + String.format("host with lock: %s, running at %s", + row.getString("host"), row.getDate("start"))); + return (0); + } + return (1); + } + + private static void deleteLock( String className) { + Row row = session.execute( String.format( "DELETE FROM authz.run_lock WHERE class = '%s' IF EXISTS", className ) ).one(); + if (! row.getBool("[applied]")) { + env.info().log( "delete failed" ); + } + } + + private static void transferVMProps(AuthzEnv env, String ... props) { + String value; + for(String key : props) { + if((value = System.getProperty(key))!=null) { + env.setProperty(key, value); + } + } + } + + // IMPORTANT! VALIDATE Organization isUser method + protected void checkOrganizationAcccess(AuthzTrans trans, Question q) throws APIException, OrganizationException { + Set testUsers = new HashSet(); + Result> rrd = q.roleDAO.readNS(trans, ROOT_NS); + if(rrd.isOK()) { + for(RoleDAO.Data r : rrd.value) { + Result> rur = q.userRoleDAO.readByRole(trans, r.fullName()); + if(rur.isOK()) { + for(UserRoleDAO.Data udd : rur.value) { + testUsers.add(udd.user); + } + } + } + } + if(testUsers.size()<2) { + throw new APIException("Not enough Users in Roles for " + ROOT_NS + " to Validate"); + } + + Identity iden; + for(String user : testUsers) { + if((iden=org.getIdentity(trans,user))==null) { + throw new APIException("Failed Organization Entity Validation Check: " + user); + } else { + trans.info().log("Organization Validation Check: " + iden.id()); + } + } + } + + protected static String logDir() { + String ld = env.getProperty(LOG_DIR); + if(ld==null) { + if(batchEnv==null) { // Deployed Batch doesn't use different ENVs, and a common logdir + ld = "logs/"; + } else { + ld = "logs/"+batchEnv; + } + } + return ld; + } + protected int count(String str, char c) { + int count=str==null||str.isEmpty()?0:1; + for(int i=str.indexOf(c);i>=0;i=str.indexOf(c,i+1)) { + ++count; + } + return count; + } + + public final void close(AuthzTrans trans) { + _close(trans); + cluster.close(); + } + + public static void main(String[] args) { + PropAccess access = new PropAccess(args); + InputStream is = null; + String filename; + String propLoc; + try { + Define.set(access); + ROOT_NS=Define.ROOT_NS(); + + File f = new File("etc/authzBatch.props"); + try { + if (f.exists()) { + filename = f.getAbsolutePath(); + is = new FileInputStream(f); + propLoc = f.getPath(); + } else { + URL rsrc = ClassLoader.getSystemResource("authBatch.props"); + filename = rsrc.toString(); + is = rsrc.openStream(); + propLoc = rsrc.getPath(); + } + access.load(is); + } finally { + if (is == null) { + System.err.println("authBatch.props must exist in etc dir, or in Classpath"); + System.exit(1); + } + is.close(); + } + + env = new AuthzEnv(access); + + transferVMProps(env, CASS_ENV, "DRY_RUN", "NS", "Organization"); + + // Flow all Env Logs to Log4j, with ENV + + LogFileNamer lfn; + if ((batchEnv = env.getProperty(CASS_ENV)) == null) { + lfn = new LogFileNamer(logDir()).noPID(); + } else { + lfn = new LogFileNamer(logDir()).noPID(); + } + + lfn.setAppender("authz-batch"); + lfn.setAppender("aspr|ASPR"); + lfn.setAppender("sync"); + lfn.setAppender("jobchange"); + lfn.setAppender("validateuser"); + aspr = Logger.getLogger("aspr"); + Log4JLogTarget.setLog4JEnv("authz-batch", env); + if (filename != null) { + env.init().log("Instantiated properties from", filename); + } + + // Log where Config found + env.info().log("Configuring from", propLoc); + propLoc = null; + + Batch batch = null; + // setup ATTUser and Organization Slots before starting this: + // TODO redo this + // env.slot(ATT.ATT_USERSLOT); + // + // OrganizationFactory.setDefaultOrg(env, ATT.class.getName()); + AuthzTrans trans = env.newTrans(); + + TimeTaken tt = trans.start("Total Run", Env.SUB); + try { + int len = args.length; + if (len > 0) { + String toolName = args[0]; + len -= 1; + if (len < 0) + len = 0; + String nargs[] = new String[len]; + if (len > 0) { + System.arraycopy(args, 1, nargs, 0, len); + } + + env.put(ssargs = env.staticSlot("ARGS"), nargs); + + /* + * Add New Batch Programs (inherit from Batch) here + */ + + // Might be a Report, Update or Temp Batch + Class cls; + String classifier = ""; + try { + cls = ClassLoader.getSystemClassLoader().loadClass("org.onap.aaf.auth.update." + toolName); + classifier = "Update:"; + } catch (ClassNotFoundException e) { + try { + cls = ClassLoader.getSystemClassLoader().loadClass("org.onap.aaf.auth.reports." + toolName); + classifier = "Report:"; + } catch (ClassNotFoundException e2) { + try { + cls = ClassLoader.getSystemClassLoader() + .loadClass("org.onap.aaf.auth.temp." + toolName); + classifier = "Temp Utility:"; + } catch (ClassNotFoundException e3) { + cls = null; + } + } + } + if (cls != null) { + Constructor cnst = cls.getConstructor(new Class[] { AuthzTrans.class }); + batch = (Batch) cnst.newInstance(trans); + env.info().log("Begin", classifier, toolName); + } + + + if (batch == null) { + trans.error().log("No Batch named", toolName, "found"); + } + /* + * End New Batch Programs (inherit from Batch) here + */ + + } + if (batch != null) { + batch.run(trans); + } + } finally { + tt.done(); + if (batch != null) { + batch.close(trans); + } + StringBuilder sb = new StringBuilder("Task Times\n"); + trans.auditTrail(4, sb, AuthzTrans.SUB, AuthzTrans.REMOTE); + trans.info().log(sb); + } + } catch (Exception e) { + e.printStackTrace(System.err); + // Exceptions thrown by DB aren't stopping the whole process. + System.exit(1); + } + } + +} + diff --git a/auth/auth-batch/src/main/java/org/onap/aaf/auth/BatchException.java b/auth/auth-batch/src/main/java/org/onap/aaf/auth/BatchException.java new file mode 100644 index 00000000..4ed0940a --- /dev/null +++ b/auth/auth-batch/src/main/java/org/onap/aaf/auth/BatchException.java @@ -0,0 +1,51 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth; + +public class BatchException extends Exception { + + /** + * + */ + private static final long serialVersionUID = -3877245367723491192L; + + public BatchException() { + } + + public BatchException(String message) { + super(message); + } + + public BatchException(Throwable cause) { + super(cause); + } + + public BatchException(String message, Throwable cause) { + super(message, cause); + } + + public BatchException(String message, Throwable cause, + boolean enableSuppression, boolean writableStackTrace) { + super(message, cause, enableSuppression, writableStackTrace); + } + +} diff --git a/auth/auth-batch/src/main/java/org/onap/aaf/auth/BatchPrincipal.java b/auth/auth-batch/src/main/java/org/onap/aaf/auth/BatchPrincipal.java new file mode 100644 index 00000000..6ca79018 --- /dev/null +++ b/auth/auth-batch/src/main/java/org/onap/aaf/auth/BatchPrincipal.java @@ -0,0 +1,41 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ +package org.onap.aaf.auth; + +import org.onap.aaf.cadi.principal.TaggedPrincipal; + +public class BatchPrincipal extends TaggedPrincipal { + private final String name; + + public BatchPrincipal(final String name) { + this.name = name; + } + + @Override + public String getName() { + return name; + } + + @Override + public String tag() { + return "Batch"; + } +} diff --git a/auth/auth-batch/src/main/java/org/onap/aaf/auth/CassBatch.java b/auth/auth-batch/src/main/java/org/onap/aaf/auth/CassBatch.java new file mode 100644 index 00000000..32e8f85d --- /dev/null +++ b/auth/auth-batch/src/main/java/org/onap/aaf/auth/CassBatch.java @@ -0,0 +1,78 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth; + +import java.io.IOException; + +import org.onap.aaf.auth.env.AuthzTrans; +import org.onap.aaf.auth.org.OrganizationException; +import org.onap.aaf.misc.env.APIException; +import org.onap.aaf.misc.env.Env; +import org.onap.aaf.misc.env.TimeTaken; +import org.onap.aaf.misc.env.impl.Log4JLogTarget; + +import com.datastax.driver.core.ResultSet; +import com.datastax.driver.core.exceptions.InvalidQueryException; + +public abstract class CassBatch extends Batch { + + protected CassBatch(AuthzTrans trans, String log4JName) throws APIException, IOException, OrganizationException { + super(trans.env()); + // Flow all Env Logs to Log4j + Log4JLogTarget.setLog4JEnv(log4JName, env); + + TimeTaken tt = trans.start("Connect to Cluster", Env.REMOTE); + try { + session = cluster.connect(); + } finally { + tt.done(); + } + } + + @Override + protected void _close(AuthzTrans trans) { + session.close(); + trans.info().log("Closed Session"); + } + + public ResultSet executeQuery(String cql) { + return executeQuery(cql,""); + } + + public ResultSet executeQuery(String cql, String extra) { + if(isDryRun() && !cql.startsWith("SELECT")) { + if(extra!=null)env.info().log("Would query" + extra + ": " + cql); + } else { + if(extra!=null)env.info().log("query" + extra + ": " + cql); + try { + return session.execute(cql); + } catch (InvalidQueryException e) { + if(extra==null) { + env.info().log("query: " + cql); + } + throw e; + } + } + return null; + } + +} \ No newline at end of file diff --git a/auth/auth-batch/src/main/java/org/onap/aaf/auth/actions/Action.java b/auth/auth-batch/src/main/java/org/onap/aaf/auth/actions/Action.java new file mode 100644 index 00000000..ad3a447d --- /dev/null +++ b/auth/auth-batch/src/main/java/org/onap/aaf/auth/actions/Action.java @@ -0,0 +1,29 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.actions; + +import org.onap.aaf.auth.env.AuthzTrans; +import org.onap.aaf.auth.layer.Result; + +public interface Action { + public Result exec(AuthzTrans trans, D data, T t); +} \ No newline at end of file diff --git a/auth/auth-batch/src/main/java/org/onap/aaf/auth/actions/ActionDAO.java b/auth/auth-batch/src/main/java/org/onap/aaf/auth/actions/ActionDAO.java new file mode 100644 index 00000000..90400015 --- /dev/null +++ b/auth/auth-batch/src/main/java/org/onap/aaf/auth/actions/ActionDAO.java @@ -0,0 +1,73 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.actions; + +import java.io.IOException; + +import org.onap.aaf.auth.dao.CassAccess; +import org.onap.aaf.auth.dao.hl.Function; +import org.onap.aaf.auth.dao.hl.Question; +import org.onap.aaf.auth.env.AuthzTrans; +import org.onap.aaf.misc.env.APIException; + +import com.datastax.driver.core.Cluster; +import com.datastax.driver.core.Session; + +public abstract class ActionDAO implements Action { + protected final Question q; + protected final Function f; + private boolean clean; + protected final boolean dryRun; + + public ActionDAO(AuthzTrans trans, Cluster cluster, boolean dryRun) throws APIException, IOException { + q = new Question(trans, cluster, CassAccess.KEYSPACE, false); + f = new Function(trans,q); + clean = true; + this.dryRun = dryRun; + } + + public ActionDAO(AuthzTrans trans, ActionDAO predecessor) { + q = predecessor.q; + f = new Function(trans,q); + clean = false; + dryRun = predecessor.dryRun; + } + + public Session getSession(AuthzTrans trans) throws APIException, IOException { + return q.historyDAO.getSession(trans); + } + + public Question question() { + return q; + } + + public Function function() { + return f; + } + + public void close(AuthzTrans trans) { + if(clean) { + q.close(trans); + } + } + +} diff --git a/auth/auth-batch/src/main/java/org/onap/aaf/auth/actions/ActionPuntDAO.java b/auth/auth-batch/src/main/java/org/onap/aaf/auth/actions/ActionPuntDAO.java new file mode 100644 index 00000000..332d2509 --- /dev/null +++ b/auth/auth-batch/src/main/java/org/onap/aaf/auth/actions/ActionPuntDAO.java @@ -0,0 +1,72 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.actions; + +import java.io.IOException; +import java.util.Date; +import java.util.GregorianCalendar; + +import org.onap.aaf.auth.env.AuthzTrans; +import org.onap.aaf.misc.env.APIException; + +import com.datastax.driver.core.Cluster; + +public abstract class ActionPuntDAO extends ActionDAO { +// private static final SecureRandom random = new SecureRandom(); + private int months; +// private int range; + protected static final Date now = new Date(); + + public ActionPuntDAO(AuthzTrans trans, Cluster cluster, int months, int range, boolean dryRun) throws APIException, IOException { + super(trans, cluster,dryRun); + this.months = months; +// this.range = range; + } + + public ActionPuntDAO(AuthzTrans trans, ActionDAO predecessor, int months, int range) { + super(trans, predecessor); + this.months = months; +// this.range = range; + } + + + protected Date puntDate(Date current) { + GregorianCalendar temp = new GregorianCalendar(); + temp.setTime(current); + temp.add(GregorianCalendar.MONTH, months); + + /* + * This method Randomized date. This is no longer needed. Just add the Punt Months. + temp.setTime(now); + temp.add(GregorianCalendar.MONTH, months); + if(range>0) { + int forward = Math.abs(random.nextInt()%range); + if(forward>1) { + temp.add(GregorianCalendar.MONTH, forward); + temp.add(GregorianCalendar.DAY_OF_MONTH, (random.nextInt()%30)-15); + } + } + */ + return temp.getTime(); + } + +} diff --git a/auth/auth-batch/src/main/java/org/onap/aaf/auth/actions/CacheTouch.java b/auth/auth-batch/src/main/java/org/onap/aaf/auth/actions/CacheTouch.java new file mode 100644 index 00000000..8261c477 --- /dev/null +++ b/auth/auth-batch/src/main/java/org/onap/aaf/auth/actions/CacheTouch.java @@ -0,0 +1,53 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.actions; + +import java.io.IOException; + +import org.onap.aaf.auth.env.AuthzTrans; +import org.onap.aaf.auth.layer.Result; +import org.onap.aaf.misc.env.APIException; + +import com.datastax.driver.core.Cluster; + +public class CacheTouch extends ActionDAO { + + public CacheTouch(AuthzTrans trans, Cluster cluster, boolean dryRun) throws APIException, IOException { + super(trans, cluster, dryRun); + } + + public CacheTouch(AuthzTrans trans, ActionDAO adao) { + super(trans, adao); + } + + @Override + public Result exec(AuthzTrans trans, String table, String text) { + if(dryRun) { + trans.info().printf("Would mark %s cache in DB for clearing: %s",table, text); + return Result.ok(); + } else { + Result rv = q.clearCache(trans, table); + trans.info().printf("Set DB Cache %s for clearing: %s",table, text); + return rv; + } + } +} \ No newline at end of file diff --git a/auth/auth-batch/src/main/java/org/onap/aaf/auth/actions/CredDelete.java b/auth/auth-batch/src/main/java/org/onap/aaf/auth/actions/CredDelete.java new file mode 100644 index 00000000..700aaaea --- /dev/null +++ b/auth/auth-batch/src/main/java/org/onap/aaf/auth/actions/CredDelete.java @@ -0,0 +1,55 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.actions; + +import java.io.IOException; + +import org.onap.aaf.auth.dao.cass.CredDAO; +import org.onap.aaf.auth.env.AuthzTrans; +import org.onap.aaf.auth.layer.Result; +import org.onap.aaf.misc.env.APIException; +import org.onap.aaf.misc.env.util.Chrono; + +import com.datastax.driver.core.Cluster; + +public class CredDelete extends ActionDAO { + + public CredDelete(AuthzTrans trans, Cluster cluster, boolean dryRun) throws APIException, IOException { + super(trans, cluster, dryRun); + } + + public CredDelete(AuthzTrans trans, ActionDAO adao) { + super(trans, adao); + } + + @Override + public Result exec(AuthzTrans trans, CredDAO.Data cred, String text) { + if(dryRun) { + trans.info().log("Would Delete:",text,cred.id,CredPrint.type(cred.type),Chrono.dateOnlyStamp(cred.expires)); + return Result.ok(); + } else { + Result rv = q.credDAO.delete(trans, cred, true); // need to read for undelete + trans.info().log("Deleted:",text,cred.id,CredPrint.type(cred.type),Chrono.dateOnlyStamp(cred.expires)); + return rv; + } + } +} \ No newline at end of file diff --git a/auth/auth-batch/src/main/java/org/onap/aaf/auth/actions/CredPrint.java b/auth/auth-batch/src/main/java/org/onap/aaf/auth/actions/CredPrint.java new file mode 100644 index 00000000..10407ce4 --- /dev/null +++ b/auth/auth-batch/src/main/java/org/onap/aaf/auth/actions/CredPrint.java @@ -0,0 +1,56 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.actions; + +import org.onap.aaf.auth.dao.cass.CredDAO; +import org.onap.aaf.auth.env.AuthzTrans; +import org.onap.aaf.auth.layer.Result; +import org.onap.aaf.misc.env.util.Chrono; + +public class CredPrint implements Action { + private String info; + + public CredPrint(String text) { + this.info = text; + } + + @Override + public Result exec(AuthzTrans trans, CredDAO.Data cred, String text) { + trans.info().log(info,cred.id,text, type(cred.type),Chrono.dateOnlyStamp(cred.expires)); + return Result.ok(); + } + + + public static String type(int type) { + switch(type) { + case CredDAO.BASIC_AUTH: // 1 + return "OLD"; + case CredDAO.BASIC_AUTH_SHA256: // 2 + return "U/P"; + case CredDAO.CERT_SHA256_RSA: // 200 + return "Cert"; + default: + return "Unknown"; + } + } + +} \ No newline at end of file diff --git a/auth/auth-batch/src/main/java/org/onap/aaf/auth/actions/CredPunt.java b/auth/auth-batch/src/main/java/org/onap/aaf/auth/actions/CredPunt.java new file mode 100644 index 00000000..78c1f892 --- /dev/null +++ b/auth/auth-batch/src/main/java/org/onap/aaf/auth/actions/CredPunt.java @@ -0,0 +1,70 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.actions; + +import java.io.IOException; +import java.util.Date; +import java.util.List; + +import org.onap.aaf.auth.dao.cass.CredDAO; +import org.onap.aaf.auth.env.AuthzTrans; +import org.onap.aaf.auth.layer.Result; +import org.onap.aaf.misc.env.APIException; +import org.onap.aaf.misc.env.util.Chrono; + +import com.datastax.driver.core.Cluster; + +public class CredPunt extends ActionPuntDAO { + + public CredPunt(AuthzTrans trans, Cluster cluster, int months, int range, boolean dryRun) throws IOException, APIException { + super(trans,cluster,months,range,dryRun); + } + + public CredPunt(AuthzTrans trans, ActionDAO adao, int months, int range) throws IOException { + super(trans, adao, months,range); + } + + public Result exec(AuthzTrans trans, CredDAO.Data cdd,String text) { + Result rv = null; + Result> read = q.credDAO.read(trans, cdd); + if(read.isOKhasData()) { + for(CredDAO.Data data : read.value) { + Date from = data.expires; + data.expires = puntDate(from); + if(data.expires.compareTo(from)<=0) { + trans.debug().printf("Error: %s is before %s", Chrono.dateOnlyStamp(data.expires), Chrono.dateOnlyStamp(from)); + } else { + if(dryRun) { + trans.info().log("Would Update Cred",cdd.id, CredPrint.type(cdd.type), "from",Chrono.dateOnlyStamp(from),"to",Chrono.dateOnlyStamp(data.expires)); + } else { + trans.info().log("Updated Cred",cdd.id, CredPrint.type(cdd.type), "from",Chrono.dateOnlyStamp(from),"to",Chrono.dateOnlyStamp(data.expires)); + rv = q.credDAO.update(trans, data); + } + } + } + } + if(rv==null) { + rv=Result.err(read); + } + return rv; + } +} \ No newline at end of file diff --git a/auth/auth-batch/src/main/java/org/onap/aaf/auth/actions/Email.java b/auth/auth-batch/src/main/java/org/onap/aaf/auth/actions/Email.java new file mode 100644 index 00000000..346e517f --- /dev/null +++ b/auth/auth-batch/src/main/java/org/onap/aaf/auth/actions/Email.java @@ -0,0 +1,220 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.actions; + +import java.io.PrintStream; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +import org.onap.aaf.auth.env.AuthzTrans; +import org.onap.aaf.auth.layer.Result; +import org.onap.aaf.auth.org.Organization; +import org.onap.aaf.auth.org.OrganizationException; +import org.onap.aaf.auth.org.Organization.Identity; +import org.onap.aaf.misc.env.util.Chrono; + +public class Email implements Action{ + protected final List toList; + protected final List ccList; + private final String[] defaultCC; + protected String subject; + private String preamble; + private Message msg; + private String sig; + protected String lineIndent=" "; + private long lastSent=0L; + + + public Email(String ... defaultCC) { + toList = new ArrayList(); + this.defaultCC = defaultCC; + ccList = new ArrayList(); + clear(); + } + + public Email clear() { + toList.clear(); + ccList.clear(); + for(String s: defaultCC) { + ccList.add(s); + } + return this; + } + + + public void indent(String indent) { + lineIndent = indent; + } + + public void preamble(String format, Object ... args) { + preamble = String.format(format, args); + } + + public Email addTo(Identity id) { + if(id!=null) { + if(!toList.contains(id.email())) { + toList.add(id.email()); + } + } + return this; + } + + public Email addTo(Collection users) { + for(String u : users) { + addTo(u); + } + return this; + } + + public Email addTo(String email) { + if(!toList.contains(email)) { + toList.add(email); + } + return this; + } + + public Email addCC(Identity id) { + if(id!=null) { + if(!ccList.contains(id.email())) { + ccList.add(id.email()); + } + } + return this; + } + + public Email addCC(String email) { + if(!ccList.contains(email)) { + ccList.add(email); + } + return this; + } + + + public Email add(Identity id, boolean toSuper) throws OrganizationException { + Identity responsible = id.responsibleTo(); + if(toSuper) { + addTo(responsible.email()); + addCC(id.email()); + } else { + addCC(responsible.email()); + addTo(id.email()); + } + return this; + } + + public Email subject(String format, Object ... args) { + if(format.contains("%s")) { + subject = String.format(format, args); + } else { + subject = format; + } + return this; + } + + + public Email signature(String format, Object ... args) { + sig = String.format(format, args); + return this; + } + + public void msg(Message msg) { + this.msg = msg; + } + + @Override + public Result exec(AuthzTrans trans, Organization org, String text) { + StringBuilder sb = new StringBuilder(); + if(preamble!=null) { + sb.append(lineIndent); + sb.append(preamble); + sb.append("\n\n"); + } + + if(msg!=null) { + msg.msg(sb,lineIndent); + sb.append("\n"); + } + + if(sig!=null) { + sb.append(sig); + sb.append("\n"); + } + + long ct = System.currentTimeMillis(); + long wait = ct-lastSent; + lastSent = ct; + if(wait < 100) { // 10 per second + try { + Thread.sleep(wait); + } catch (InterruptedException e) { + } + } + return exec(trans,org,sb); + } + + protected Result exec(AuthzTrans trans, Organization org, StringBuilder sb) { + try { + /* int status = */ + org.sendEmail(trans, + toList, + ccList, + subject, + sb.toString(), + false); + } catch (Exception e) { + return Result.err(Result.ERR_ActionNotCompleted,e.getMessage()); + } + return Result.ok(); + + } + + public void log(PrintStream ps, String text) { + ps.print(Chrono.dateTime()); + boolean first = true; + for(String s : toList) { + if(first) { + first = false; + ps.print(": "); + } else { + ps.print(", "); + } + ps.print(s); + } + if(!ccList.isEmpty()) { + first=true; + for(String s : ccList) { + if(first) { + first = false; + ps.print(" ["); + } else { + ps.print(", "); + } + ps.print(s); + } + ps.print(']'); + } + + ps.print(' '); + ps.println(text); + } +} diff --git a/auth/auth-batch/src/main/java/org/onap/aaf/auth/actions/EmailPrint.java b/auth/auth-batch/src/main/java/org/onap/aaf/auth/actions/EmailPrint.java new file mode 100644 index 00000000..dba02426 --- /dev/null +++ b/auth/auth-batch/src/main/java/org/onap/aaf/auth/actions/EmailPrint.java @@ -0,0 +1,98 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.actions; + +import java.io.PrintStream; + +import org.onap.aaf.auth.env.AuthzTrans; +import org.onap.aaf.auth.layer.Result; +import org.onap.aaf.auth.org.Organization; + +public class EmailPrint extends Email { + + private static final int LINE_LENGTH = 100; + + public EmailPrint(String... defaultCC) { + super(defaultCC); + } + + /* (non-Javadoc) + * @see org.onap.aaf.auth.actions.Email#exec(org.onap.aaf.auth.org.test.Organization, java.lang.StringBuilder) + */ + @Override + protected Result exec(AuthzTrans trans, Organization org, StringBuilder msg) { + PrintStream out = System.out; + boolean first = true; + out.print("To: "); + for(String s: toList) { + if(first) {first = false;} + else {out.print(',');} + out.print(s); + } + out.println(); + + first = true; + out.print("CC: "); + for(String s: ccList) { + if(first) {first = false;} + else {out.print(',');} + out.print(s); + } + out.println(); + + out.print("Subject: "); + out.println(subject); + out.println(); + boolean go = true; + + for(int start=0, end=LINE_LENGTH;go;start=end,end=Math.min(msg.length(), start+LINE_LENGTH)) { + int ret = msg.indexOf("\n",start+1); + switch(ret) { + case -1: + out.println(msg.substring(start,end)); + break; + case 0: + end=start+1; + out.println(); + break; + default: + if(retstart && ret { + private String info; + + public FuturePrint(String text) { + this.info = text; + } + + @Override + public Result exec(AuthzTrans trans, Future f, String text) { + trans.info().log(info,f.id(),f.memo(),"expiring on",Chrono.dateOnlyStamp(f.expires())); + return Result.ok(); + } +} \ No newline at end of file diff --git a/auth/auth-batch/src/main/java/org/onap/aaf/auth/actions/Key.java b/auth/auth-batch/src/main/java/org/onap/aaf/auth/actions/Key.java new file mode 100644 index 00000000..8c39e47d --- /dev/null +++ b/auth/auth-batch/src/main/java/org/onap/aaf/auth/actions/Key.java @@ -0,0 +1,26 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.actions; + +public interface Key { + public String key(HELPER H); +} diff --git a/auth/auth-batch/src/main/java/org/onap/aaf/auth/actions/Message.java b/auth/auth-batch/src/main/java/org/onap/aaf/auth/actions/Message.java new file mode 100644 index 00000000..98fc0054 --- /dev/null +++ b/auth/auth-batch/src/main/java/org/onap/aaf/auth/actions/Message.java @@ -0,0 +1,53 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.actions; + +import java.util.ArrayList; +import java.util.List; + +public class Message { + public final List lines; + + public Message() { + lines = new ArrayList(); + } + + public void clear() { + lines.clear(); + } + + public String line(String format, Object ... args) { + String rv=String.format(format, args); + lines.add(rv); + return rv; + } + + public void msg(StringBuilder sb, String lineIndent) { + if(lines.size()>0) { + for(String line : lines) { + sb.append(lineIndent); + sb.append(line); + sb.append('\n'); + } + } + } +} diff --git a/auth/auth-batch/src/main/java/org/onap/aaf/auth/actions/NSACreate.java b/auth/auth-batch/src/main/java/org/onap/aaf/auth/actions/NSACreate.java new file mode 100644 index 00000000..3d215871 --- /dev/null +++ b/auth/auth-batch/src/main/java/org/onap/aaf/auth/actions/NSACreate.java @@ -0,0 +1,58 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.actions; + +import java.io.IOException; + +import org.onap.aaf.auth.env.AuthzTrans; +import org.onap.aaf.auth.helpers.NsAttrib; +import org.onap.aaf.auth.layer.Result; +import org.onap.aaf.misc.env.APIException; + +import com.datastax.driver.core.Cluster; + +public class NSACreate extends ActionDAO { + public NSACreate(AuthzTrans trans, Cluster cluster, boolean dryRun) throws APIException, IOException { + super(trans, cluster,dryRun); + } + + public NSACreate(AuthzTrans trans, ActionDAO adao) { + super(trans, adao); + } + + @Override + public Result exec(AuthzTrans trans, NsAttrib nsa, String text) { + if(dryRun) { + trans.info().printf("Would Create %s Attrib '%s=%s' in %s",text,nsa.key,nsa.value,nsa.ns); + return Result.ok(); + } else { + Result rv = q.nsDAO.dao().attribAdd(trans, nsa.ns, nsa.key, nsa.value); + if(rv.isOK()) { + trans.info().printf("%s - Created Attrib '%s=%s' in %s",text,nsa.key,nsa.value,nsa.ns); + } else { + trans.error().printf("Error Creating Attrib '%s=%s' in %s - %s",nsa.key,nsa.value,nsa.ns,rv.details); + } + return rv; + } + } + +} \ No newline at end of file diff --git a/auth/auth-batch/src/main/java/org/onap/aaf/auth/actions/NSADelete.java b/auth/auth-batch/src/main/java/org/onap/aaf/auth/actions/NSADelete.java new file mode 100644 index 00000000..4b976822 --- /dev/null +++ b/auth/auth-batch/src/main/java/org/onap/aaf/auth/actions/NSADelete.java @@ -0,0 +1,58 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.actions; + +import java.io.IOException; + +import org.onap.aaf.auth.env.AuthzTrans; +import org.onap.aaf.auth.helpers.NsAttrib; +import org.onap.aaf.auth.layer.Result; +import org.onap.aaf.misc.env.APIException; + +import com.datastax.driver.core.Cluster; + +public class NSADelete extends ActionDAO { + public NSADelete(AuthzTrans trans, Cluster cluster, boolean dryRun) throws APIException, IOException { + super(trans, cluster,dryRun); + } + + public NSADelete(AuthzTrans trans, ActionDAO adao) { + super(trans, adao); + } + + @Override + public Result exec(AuthzTrans trans, NsAttrib nsa, String text) { + if(dryRun) { + trans.info().printf("Would Delete %s Attrib '%s' in %s",text,nsa.key,nsa.ns); + return Result.ok(); + } else { + Result rv = q.nsDAO.dao().attribRemove(trans, nsa.ns, nsa.key); + if(rv.isOK()) { + trans.info().printf("%s - Deleted Attrib '%s' in %s",text,nsa.key,nsa.value,nsa.ns); + } else { + trans.error().printf("Error Deleting Attrib '%s' in %s - %s",nsa.key,nsa.value,nsa.ns,rv.details); + } + return rv; + } + } + +} \ No newline at end of file diff --git a/auth/auth-batch/src/main/java/org/onap/aaf/auth/actions/NSDescUpdate.java b/auth/auth-batch/src/main/java/org/onap/aaf/auth/actions/NSDescUpdate.java new file mode 100644 index 00000000..368c8452 --- /dev/null +++ b/auth/auth-batch/src/main/java/org/onap/aaf/auth/actions/NSDescUpdate.java @@ -0,0 +1,58 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.actions; + +import java.io.IOException; + +import org.onap.aaf.auth.env.AuthzTrans; +import org.onap.aaf.auth.helpers.NS; +import org.onap.aaf.auth.layer.Result; +import org.onap.aaf.misc.env.APIException; + +import com.datastax.driver.core.Cluster; + +public class NSDescUpdate extends ActionDAO { + public NSDescUpdate(AuthzTrans trans, Cluster cluster, boolean dryRun) throws APIException, IOException { + super(trans, cluster,dryRun); + } + + public NSDescUpdate(AuthzTrans trans, ActionDAO adao) { + super(trans, adao); + } + + @Override + public Result exec(AuthzTrans trans, NS ns, String desc) { + if(dryRun) { + trans.info().printf("Would Update '%s' Description to '%s'",ns,desc); + return Result.ok(); + } else { + Result rv = q.nsDAO.dao().addDescription(trans, ns.name, desc); + if(rv.isOK()) { + trans.info().printf("Updated '%s' Description to '%s'",ns,desc); + } else { + trans.error().printf("Error Updating '%s' Description to '%s' - %s",ns,desc,rv.details); + } + return rv; + } + } + +} \ No newline at end of file diff --git a/auth/auth-batch/src/main/java/org/onap/aaf/auth/actions/PermCreate.java b/auth/auth-batch/src/main/java/org/onap/aaf/auth/actions/PermCreate.java new file mode 100644 index 00000000..5f3ab202 --- /dev/null +++ b/auth/auth-batch/src/main/java/org/onap/aaf/auth/actions/PermCreate.java @@ -0,0 +1,69 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.actions; + +import java.io.IOException; + +import org.onap.aaf.auth.dao.cass.PermDAO; +import org.onap.aaf.auth.dao.cass.PermDAO.Data; +import org.onap.aaf.auth.env.AuthzTrans; +import org.onap.aaf.auth.helpers.Perm; +import org.onap.aaf.auth.layer.Result; +import org.onap.aaf.misc.env.APIException; + +import com.datastax.driver.core.Cluster; + + +public class PermCreate extends ActionDAO { + public PermCreate(AuthzTrans trans, Cluster cluster, boolean dryRun) throws APIException, IOException { + super(trans, cluster, dryRun); + } + + public PermCreate(AuthzTrans trans, ActionDAO adao) { + super(trans, adao); + } + + @Override + public Result exec(AuthzTrans trans, Perm p,String text) { + PermDAO.Data pdd = new PermDAO.Data(); + pdd.ns = p.ns; + pdd.type = p.type; + pdd.instance = p.instance; + pdd.action = p.action; + pdd.description = p.description; + pdd.roles = p.roles; + + if(dryRun) { + trans.info().log("Would Create Perm:",text,p.fullType()); + return Result.ok(pdd); + } else { + Result rv = q.permDAO.create(trans, pdd); // need to read for undelete + if(rv.isOK()) { + trans.info().log("Created Perm:",text,p.fullType()); + } else { + trans.error().log("Error Creating Role -",rv.details,":",p.fullType()); + } + return rv; + } + } + +} \ No newline at end of file diff --git a/auth/auth-batch/src/main/java/org/onap/aaf/auth/actions/PermDelete.java b/auth/auth-batch/src/main/java/org/onap/aaf/auth/actions/PermDelete.java new file mode 100644 index 00000000..02fd3c6c --- /dev/null +++ b/auth/auth-batch/src/main/java/org/onap/aaf/auth/actions/PermDelete.java @@ -0,0 +1,64 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.actions; + +import java.io.IOException; + +import org.onap.aaf.auth.dao.cass.PermDAO; +import org.onap.aaf.auth.env.AuthzTrans; +import org.onap.aaf.auth.helpers.Perm; +import org.onap.aaf.auth.layer.Result; +import org.onap.aaf.misc.env.APIException; + +import com.datastax.driver.core.Cluster; + +public class PermDelete extends ActionDAO { + public PermDelete(AuthzTrans trans, Cluster cluster, boolean dryRun) throws APIException, IOException { + super(trans, cluster, dryRun); + } + + public PermDelete(AuthzTrans trans, ActionDAO adao) { + super(trans, adao); + } + + @Override + public Result exec(AuthzTrans trans, Perm p,String text) { + PermDAO.Data pdd = new PermDAO.Data(); + pdd.ns = p.ns; + pdd.type = p.type; + pdd.instance = p.instance; + pdd.action = p.action; + if(dryRun) { + trans.info().log("Would Delete Perm:",text,p.fullType()); + return Result.ok(); + } else { + Result rv = q.permDAO.delete(trans, pdd, true); // need to read for undelete + if(rv.isOK()) { + trans.info().log("Deleted Perm:",text,p.fullType()); + } else { + trans.error().log("Error Deleting Perm -",rv.details,":",p.fullType()); + } + return rv; + } + } + +} \ No newline at end of file diff --git a/auth/auth-batch/src/main/java/org/onap/aaf/auth/actions/PermModify.java b/auth/auth-batch/src/main/java/org/onap/aaf/auth/actions/PermModify.java new file mode 100644 index 00000000..9b60cee1 --- /dev/null +++ b/auth/auth-batch/src/main/java/org/onap/aaf/auth/actions/PermModify.java @@ -0,0 +1,141 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.actions; + +import java.io.IOException; +import java.util.List; + +import org.onap.aaf.auth.dao.cass.PermDAO; +import org.onap.aaf.auth.dao.cass.RoleDAO; +import org.onap.aaf.auth.dao.cass.Status; +import org.onap.aaf.auth.dao.cass.PermDAO.Data; +import org.onap.aaf.auth.env.AuthzTrans; +import org.onap.aaf.auth.helpers.Perm; +import org.onap.aaf.auth.helpers.Role; +import org.onap.aaf.auth.layer.Result; +import org.onap.aaf.misc.env.APIException; + +import com.datastax.driver.core.Cluster; + +public class PermModify extends ActionDAO { + public PermModify(AuthzTrans trans, Cluster cluster, boolean dryRun) throws APIException, IOException { + super(trans, cluster,dryRun); + } + + public PermModify(AuthzTrans trans, ActionDAO adao) { + super(trans, adao); + } + + @Override + public Result exec(AuthzTrans trans, final Perm p, final Modify modify) { + Result> rr = q.permDAO.read(trans, p.ns,p.type,p.instance,p.action); + if(dryRun) { + if(rr.isOKhasData()) { + return Result.ok(rr.value.get(0)); + } else { + return Result.err(Result.ERR_NotFound, "Data not Found " + p.toString()); + } + } else { + Result rv = null; + if(rr.isOKhasData()) { + for(final Data d : rr.value) { + modify.change(d); + if(d.ns.equals(p.ns) && d.type.equals(p.type) && d.instance.equals(p.instance) && d.action.equals(p.action)) { + // update for fields + // In either case, adjust Permissions + for(String r : d.roles) { + if(!p.roles.contains(r)) { + q.permDAO.dao().addRole(trans, d, r); + } + } + for(String r : p.roles) { + if(!d.roles.contains(r)) { + q.permDAO.dao().delRole(trans, d, r); + } + } + rv = Result.ok(d); + } else { + for(String r : d.roles) { + Role role = Role.keys.get(r); + if(role.perms.contains(p.encode())) { + modify.roleModify().exec(trans, role, new RoleModify.Modify() { + @Override + public PermModify permModify() { + return PermModify.this; + } + + @Override + public void change(RoleDAO.Data rdd) { + rdd.perms.remove(p.encode()); + rdd.perms.add(d.encode()); + } + }); + } + } + + rv = q.permDAO.create(trans, d); + if(rv.isOK()) { + PermDAO.Data pdd = new PermDAO.Data(); + pdd.ns = p.ns; + pdd.type = p.type; + pdd.instance = p.instance; + pdd.action = p.action; + q.permDAO.delete(trans, pdd, false); + trans.info().printf("Updated %s|%s|%s|%s to %s|%s|%s|%s\n", + p.ns, p.type, p.instance, p.action, + d.ns, d.type, d.instance, d.action); + } else { + trans.info().log(rv.errorString()); + } + } + + } + } else { + rv = Result.err(rr); + } + if(rv==null) { + rv = Result.err(Status.ERR_General,"Never get to this code"); + } + + return rv; + } + } + + public static interface Modify { + void change(PermDAO.Data ur); + RoleModify roleModify(); + } + + public Result delete(AuthzTrans trans, Perm p) { + if(dryRun) { + return Result.ok(); + } else { + PermDAO.Data data = new PermDAO.Data(); + data.ns=p.ns; + data.type = p.type; + data.instance = p.instance; + data.action = p.action; + return q.permDAO.delete(trans,data,false); + } + } + +} \ No newline at end of file diff --git a/auth/auth-batch/src/main/java/org/onap/aaf/auth/actions/RoleCreate.java b/auth/auth-batch/src/main/java/org/onap/aaf/auth/actions/RoleCreate.java new file mode 100644 index 00000000..50d163ab --- /dev/null +++ b/auth/auth-batch/src/main/java/org/onap/aaf/auth/actions/RoleCreate.java @@ -0,0 +1,66 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.actions; + +import java.io.IOException; + +import org.onap.aaf.auth.dao.cass.RoleDAO; +import org.onap.aaf.auth.dao.cass.RoleDAO.Data; +import org.onap.aaf.auth.env.AuthzTrans; +import org.onap.aaf.auth.helpers.Role; +import org.onap.aaf.auth.layer.Result; +import org.onap.aaf.misc.env.APIException; + +import com.datastax.driver.core.Cluster; + +public class RoleCreate extends ActionDAO { + public RoleCreate(AuthzTrans trans, Cluster cluster, boolean dryRun) throws APIException, IOException { + super(trans, cluster,dryRun); + } + + public RoleCreate(AuthzTrans trans, ActionDAO adao) { + super(trans, adao); + } + + @Override + public Result exec(AuthzTrans trans, Role r,String text) { + RoleDAO.Data rdd = new RoleDAO.Data(); + rdd.ns = r.ns; + rdd.name = r.name; + rdd.description = r.description; + rdd.perms = r.perms; + + if(dryRun) { + trans.info().log("Would Create Role:",text,r.fullName()); + return Result.ok(rdd); + } else { + Result rv = q.roleDAO.create(trans, rdd); // need to read for undelete + if(rv.isOK()) { + trans.info().log("Created Role:",text,r.fullName()); + } else { + trans.error().log("Error Creating Role -",rv.details,":",r.fullName()); + } + return rv; + } + } + +} \ No newline at end of file diff --git a/auth/auth-batch/src/main/java/org/onap/aaf/auth/actions/RoleDelete.java b/auth/auth-batch/src/main/java/org/onap/aaf/auth/actions/RoleDelete.java new file mode 100644 index 00000000..cbe3c1c5 --- /dev/null +++ b/auth/auth-batch/src/main/java/org/onap/aaf/auth/actions/RoleDelete.java @@ -0,0 +1,62 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.actions; + +import java.io.IOException; + +import org.onap.aaf.auth.dao.cass.RoleDAO; +import org.onap.aaf.auth.env.AuthzTrans; +import org.onap.aaf.auth.helpers.Role; +import org.onap.aaf.auth.layer.Result; +import org.onap.aaf.misc.env.APIException; + +import com.datastax.driver.core.Cluster; + +public class RoleDelete extends ActionDAO { + public RoleDelete(AuthzTrans trans, Cluster cluster, boolean dryRun) throws APIException, IOException { + super(trans, cluster, dryRun); + } + + public RoleDelete(AuthzTrans trans, ActionDAO adao) { + super(trans, adao); + } + + @Override + public Result exec(AuthzTrans trans, Role r,String text) { + if(dryRun) { + trans.info().log("Would Delete Role:",text,r.fullName()); + return Result.ok(); + } else { + RoleDAO.Data rdd = new RoleDAO.Data(); + rdd.ns = r.ns; + rdd.name = r.name; + Result rv = q.roleDAO.delete(trans, rdd, true); // need to read for undelete + if(rv.isOK()) { + trans.info().log("Deleted Role:",text,r.fullName()); + } else { + trans.error().log("Error Deleting Role -",rv.details,":",r.fullName()); + } + return rv; + } + } + +} \ No newline at end of file diff --git a/auth/auth-batch/src/main/java/org/onap/aaf/auth/actions/RoleModify.java b/auth/auth-batch/src/main/java/org/onap/aaf/auth/actions/RoleModify.java new file mode 100644 index 00000000..c72a9d8f --- /dev/null +++ b/auth/auth-batch/src/main/java/org/onap/aaf/auth/actions/RoleModify.java @@ -0,0 +1,152 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.actions; + +import java.io.IOException; +import java.util.List; + +import org.onap.aaf.auth.dao.cass.PermDAO; +import org.onap.aaf.auth.dao.cass.RoleDAO; +import org.onap.aaf.auth.dao.cass.Status; +import org.onap.aaf.auth.dao.cass.RoleDAO.Data; +import org.onap.aaf.auth.env.AuthzTrans; +import org.onap.aaf.auth.helpers.Perm; +import org.onap.aaf.auth.helpers.Role; +import org.onap.aaf.auth.layer.Result; +import org.onap.aaf.misc.env.APIException; + +import com.datastax.driver.core.Cluster; + +public class RoleModify extends ActionDAO { + public RoleModify(AuthzTrans trans, Cluster cluster, boolean dryRun) throws APIException, IOException { + super(trans, cluster, dryRun); + } + + public RoleModify(AuthzTrans trans, ActionDAO adao) { + super(trans, adao); + } + + @Override + public Result exec(final AuthzTrans trans, final Role r,final RoleModify.Modify modify) { + Result> rr = q.roleDAO.read(trans, r.ns,r.name); + if(dryRun) { + if(rr.isOKhasData()) { + return Result.ok(rr.value.get(0)); + } else { + return Result.err(Result.ERR_NotFound, "Data not Found " + r.toString()); + } + } else { + Result rv = null; + if(rr.isOKhasData()) { + for(final Data d : rr.value) { + modify.change(d); + if(d.ns.equals(r.ns) && d.name.equals(r.name)) { + // update for fields + // In either case, adjust Roles + for(String p : d.perms) { + if(!r.perms.contains(p)) { + Result rpdd = PermDAO.Data.decode(trans, q, p); + if(rpdd.isOKhasData()) { + q.roleDAO.dao().addPerm(trans, d, rpdd.value); + } + } + } + for(String p : r.perms) { + if(!d.perms.contains(p)) { + Result rpdd = PermDAO.Data.decode(trans, q, p); + if(rpdd.isOKhasData()) { + q.roleDAO.dao().delPerm(trans, d, rpdd.value); + } + } + } + rv = Result.ok(d); + } else { + for(String p : d.perms) { + Perm perm = Perm.keys.get(p); + if(perm!=null) { + if(perm.roles.contains(r.encode())) { + modify.permModify().exec(trans, perm, new PermModify.Modify() { + @Override + public RoleModify roleModify() { + return RoleModify.this; + } + + @Override + public void change(PermDAO.Data pdd) { + pdd.roles.remove(r.encode()); + pdd.roles.add(d.encode()); + } + }); + } + } + } + Result> preexist = q.roleDAO.read(trans, d); + if(preexist.isOKhasData()) { + Data rdd = preexist.value.get(0); + for(String p : d.perms) { + Result perm = PermDAO.Data.decode(trans, q, p); + if(perm.isOKhasData()) { + q.roleDAO.dao().addPerm(trans,rdd, perm.value); + } + } + rv = Result.ok(rdd); + } else { + rv = q.roleDAO.create(trans, d); + } + if(rv.isOK()) { + trans.info().printf("Updating %s|%s to %s|%s", r.ns, r.name, d.ns, d.name); + RoleDAO.Data rmme = new RoleDAO.Data(); + rmme.ns=r.ns; + rmme.name=r.name; + q.roleDAO.delete(trans, rmme, false); + + } else { + trans.info().log(rv.errorString()); + } + } + } + } else { + rv = Result.err(rr); + } + if(rv==null) { + rv = Result.err(Status.ERR_General,"Never get to this code"); + } + return rv; + } + } + + public static interface Modify { + void change(RoleDAO.Data ur); + PermModify permModify(); + } + + public Result delete(AuthzTrans trans, Role r) { + if(dryRun) { + return Result.ok(); + } else { + RoleDAO.Data data = new RoleDAO.Data(); + data.ns=r.ns; + data.name = r.name; + return q.roleDAO.delete(trans,data,false); + } + } +} \ No newline at end of file diff --git a/auth/auth-batch/src/main/java/org/onap/aaf/auth/actions/URAdd.java b/auth/auth-batch/src/main/java/org/onap/aaf/auth/actions/URAdd.java new file mode 100644 index 00000000..50a5a8f0 --- /dev/null +++ b/auth/auth-batch/src/main/java/org/onap/aaf/auth/actions/URAdd.java @@ -0,0 +1,57 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.actions; + +import java.io.IOException; + +import org.onap.aaf.auth.dao.cass.UserRoleDAO; +import org.onap.aaf.auth.dao.cass.UserRoleDAO.Data; +import org.onap.aaf.auth.env.AuthzTrans; +import org.onap.aaf.auth.helpers.UserRole; +import org.onap.aaf.auth.layer.Result; +import org.onap.aaf.misc.env.APIException; +import org.onap.aaf.misc.env.util.Chrono; + +import com.datastax.driver.core.Cluster; + +public class URAdd extends ActionDAO { + public URAdd(AuthzTrans trans, Cluster cluster, boolean dryRun) throws APIException, IOException { + super(trans, cluster,dryRun); + } + + public URAdd(AuthzTrans trans, ActionDAO adao) { + super(trans, adao); + } + + @Override + public Result exec(AuthzTrans trans, UserRole ur, String text) { + if(dryRun) { + trans.info().log("Would Add:",text,ur.role(),ur.user(),"on",Chrono.dateOnlyStamp(ur.expires())); + return Result.ok(ur.urdd()); + } else { + Result rv = q.userRoleDAO.create(trans, ur.urdd()); + trans.info().log("Added:",text,ur.role(),ur.user(),"on",Chrono.dateOnlyStamp(ur.expires())); + return rv; + } + } + +} \ No newline at end of file diff --git a/auth/auth-batch/src/main/java/org/onap/aaf/auth/actions/URDelete.java b/auth/auth-batch/src/main/java/org/onap/aaf/auth/actions/URDelete.java new file mode 100644 index 00000000..9bc7da49 --- /dev/null +++ b/auth/auth-batch/src/main/java/org/onap/aaf/auth/actions/URDelete.java @@ -0,0 +1,59 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.actions; + +import java.io.IOException; + +import org.onap.aaf.auth.env.AuthzTrans; +import org.onap.aaf.auth.helpers.UserRole; +import org.onap.aaf.auth.layer.Result; +import org.onap.aaf.misc.env.APIException; +import org.onap.aaf.misc.env.util.Chrono; + +import com.datastax.driver.core.Cluster; + +public class URDelete extends ActionDAO { + public URDelete(AuthzTrans trans, Cluster cluster, boolean dryRun) throws APIException, IOException { + super(trans, cluster,dryRun); + } + + public URDelete(AuthzTrans trans, ActionDAO adao) { + super(trans, adao); + } + + @Override + public Result exec(AuthzTrans trans, UserRole ur,String text) { + if(dryRun) { + trans.info().log("Would Delete UserRole:",text,ur.user(),ur.role(),"on",Chrono.dateOnlyStamp(ur.expires())); + return Result.ok(); + } else { + Result rv = q.userRoleDAO.delete(trans,ur.urdd(), true); // need to read for undelete + if(rv.isOK()) { + trans.info().log("Deleted UserRole:",text,ur.user(),ur.role(),"on",Chrono.dateOnlyStamp(ur.expires())); + } else { + trans.error().log("Error Deleting User Role -",rv.details,":",ur.user(),ur.role(),"on",Chrono.dateOnlyStamp(ur.expires()) ); + } + return rv; + } + } + +} \ No newline at end of file diff --git a/auth/auth-batch/src/main/java/org/onap/aaf/auth/actions/URFutureApprove.java b/auth/auth-batch/src/main/java/org/onap/aaf/auth/actions/URFutureApprove.java new file mode 100644 index 00000000..17d9cc01 --- /dev/null +++ b/auth/auth-batch/src/main/java/org/onap/aaf/auth/actions/URFutureApprove.java @@ -0,0 +1,111 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.actions; + +import java.io.IOException; +import java.util.Date; +import java.util.GregorianCalendar; + +import org.onap.aaf.auth.dao.cass.FutureDAO; +import org.onap.aaf.auth.dao.cass.NsDAO; +import org.onap.aaf.auth.dao.hl.Function; +import org.onap.aaf.auth.dao.hl.Question; +import org.onap.aaf.auth.dao.hl.Function.FUTURE_OP; +import org.onap.aaf.auth.env.AuthzTrans; +import org.onap.aaf.auth.helpers.Approval; +import org.onap.aaf.auth.helpers.UserRole; +import org.onap.aaf.auth.layer.Result; +import org.onap.aaf.auth.org.Organization.Expiration; +import org.onap.aaf.misc.env.APIException; +import org.onap.aaf.misc.env.util.Chrono; + +import com.datastax.driver.core.Cluster; + +public class URFutureApprove extends ActionDAO implements Action, Key { + private final Date start, expires; + + public URFutureApprove(AuthzTrans trans, Cluster cluster, boolean dryRun) throws APIException, IOException { + super(trans,cluster, dryRun); + GregorianCalendar gc = new GregorianCalendar(); + start = gc.getTime(); + expires = trans.org().expiration(gc, Expiration.Future).getTime(); + } + + public URFutureApprove(AuthzTrans trans, ActionDAO adao) { + super(trans, adao); + GregorianCalendar gc = new GregorianCalendar(); + start = gc.getTime(); + expires = trans.org().expiration(gc, Expiration.Future).getTime(); + } + + @Override + public Result exec(AuthzTrans trans, UserRole ur,String text) { + if(dryRun) { + return Result.ok(text); + } else { + Result rns = q.deriveNs(trans, ur.ns()); + if(rns.isOK()) { + + FutureDAO.Data data = new FutureDAO.Data(); + data.id=null; // let Create function assign UUID + data.target=Function.FOP_USER_ROLE; + + data.memo = key(ur); + data.start = start; + data.expires = ur.expires(); + try { + data.construct = ur.urdd().bytify(); + } catch (IOException e) { + return Result.err(e); + } + Result rfuture = f.createFuture(trans, data, Function.FOP_USER_ROLE, ur.user(), rns.value, FUTURE_OP.A); + if(rfuture.isOK()) { + trans.info().log(rfuture.value, text, ur.user(), data.memo); + } else { + trans.error().log(rfuture.details, text); + } + return rfuture; + } else { + return Result.err(rns); + } + } + } + + @Override + public String key(UserRole ur) { + String expire; + if(expires.before(start)) { + expire = "' - EXPIRED "; + } else { + expire = "' - expiring "; + } + + if(Question.OWNER.equals(ur.rname())) { + return Approval.RE_VALIDATE_OWNER + ur.ns() + expire + Chrono.dateOnlyStamp(ur.expires()); + } else if(Question.ADMIN.equals(ur.rname())) { + return Approval.RE_VALIDATE_ADMIN + ur.ns() + expire + Chrono.dateOnlyStamp(ur.expires()); + } else { + return Approval.RE_APPROVAL_IN_ROLE + ur.role() + expire + Chrono.dateOnlyStamp(ur.expires()); + } + } + +} \ No newline at end of file diff --git a/auth/auth-batch/src/main/java/org/onap/aaf/auth/actions/URFutureApproveExec.java b/auth/auth-batch/src/main/java/org/onap/aaf/auth/actions/URFutureApproveExec.java new file mode 100644 index 00000000..6cf2c53e --- /dev/null +++ b/auth/auth-batch/src/main/java/org/onap/aaf/auth/actions/URFutureApproveExec.java @@ -0,0 +1,108 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.actions; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +import org.onap.aaf.auth.dao.cass.ApprovalDAO; +import org.onap.aaf.auth.dao.cass.UserRoleDAO; +import org.onap.aaf.auth.dao.cass.ApprovalDAO.Data; +import org.onap.aaf.auth.dao.hl.Function.FUTURE_OP; +import org.onap.aaf.auth.dao.hl.Function.Lookup; +import org.onap.aaf.auth.dao.hl.Function.OP_STATUS; +import org.onap.aaf.auth.env.AuthzTrans; +import org.onap.aaf.auth.helpers.Approval; +import org.onap.aaf.auth.helpers.Future; +import org.onap.aaf.auth.helpers.UserRole; +import org.onap.aaf.auth.layer.Result; +import org.onap.aaf.misc.env.APIException; + +import com.datastax.driver.core.Cluster; + +public class URFutureApproveExec extends ActionDAO, OP_STATUS, Future> { + + public URFutureApproveExec(AuthzTrans trans, Cluster cluster, boolean dryRun) throws APIException, IOException { + super(trans,cluster, dryRun); + } + + public URFutureApproveExec(AuthzTrans trans, ActionDAO adao) { + super(trans, adao); + } + + @Override + public Result exec(AuthzTrans trans, List app, Future future) { + if(dryRun) { + return Result.err(Result.ERR_ActionNotCompleted,"Not Executed"); + } else { + // Save on Lookups + final List apprs = new ArrayList(); + final List urs = new ArrayList(); + for(Approval a : app) { + apprs.add(a.add); + UserRole ur = UserRole.get(a.add.user, future.role); + if(ur!=null) { + urs.add(ur.urdd()); + } + } + Result rv = f.performFutureOp(trans, FUTURE_OP.A, future.fdd, + new Lookup>() { + @Override + public List get(AuthzTrans trans, Object ... noop) { + return apprs; + } + }, + new Lookup() { + @Override + public UserRoleDAO.Data get(AuthzTrans trans, Object ... keys) { + List lur = UserRole.byUser.get(keys[0]); + if(lur!=null) { + for(UserRole ur : lur) { + if(ur.role().equals(keys[1])) { + return ur.urdd(); + } + } + } + return null; + } + }); + if(rv.isOK()) { + switch(rv.value) { + case D: + trans.info().printf("Denied %s on %s", future.memo(),future.fdd.target); + break; + case E: + trans.info().printf("Completed %s on %s", future.memo(),future.fdd.target); + break; + case L: + trans.info().printf("Future %s on %s has lapsed", future.memo(),future.fdd.target); + break; + default: + } + } else { + trans.error().log("Error completing",future.memo(),rv.errorString()); + } + return rv; + } + } +} \ No newline at end of file diff --git a/auth/auth-batch/src/main/java/org/onap/aaf/auth/actions/URFuturePrint.java b/auth/auth-batch/src/main/java/org/onap/aaf/auth/actions/URFuturePrint.java new file mode 100644 index 00000000..83a24c21 --- /dev/null +++ b/auth/auth-batch/src/main/java/org/onap/aaf/auth/actions/URFuturePrint.java @@ -0,0 +1,41 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.actions; + +import org.onap.aaf.auth.env.AuthzTrans; +import org.onap.aaf.auth.helpers.UserRole; +import org.onap.aaf.auth.layer.Result; +import org.onap.aaf.misc.env.util.Chrono; + + +public class URFuturePrint implements Action { + private String info; + + public URFuturePrint(String text) { + this.info = text; + } + + @Override + public Result exec(AuthzTrans trans, UserRole ur, String text) { + trans.info().log(info,text,ur.user(),"to",ur.role(),"on",Chrono.dateOnlyStamp(ur.expires())); + return Result.ok(info); + }} \ No newline at end of file diff --git a/auth/auth-batch/src/main/java/org/onap/aaf/auth/actions/URModify.java b/auth/auth-batch/src/main/java/org/onap/aaf/auth/actions/URModify.java new file mode 100644 index 00000000..3f65a6a4 --- /dev/null +++ b/auth/auth-batch/src/main/java/org/onap/aaf/auth/actions/URModify.java @@ -0,0 +1,80 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.actions; + +import java.io.IOException; +import java.util.List; + +import org.onap.aaf.auth.dao.cass.Status; +import org.onap.aaf.auth.dao.cass.UserRoleDAO; +import org.onap.aaf.auth.dao.cass.UserRoleDAO.Data; +import org.onap.aaf.auth.env.AuthzTrans; +import org.onap.aaf.auth.helpers.UserRole; +import org.onap.aaf.auth.layer.Result; +import org.onap.aaf.misc.env.APIException; + +import com.datastax.driver.core.Cluster; + +public class URModify extends ActionDAO { + public URModify(AuthzTrans trans, Cluster cluster, boolean dryRun) throws APIException, IOException { + super(trans, cluster,dryRun); + } + + public URModify(AuthzTrans trans, ActionDAO adao) { + super(trans, adao); + } + + @Override + public Result exec(AuthzTrans trans, UserRole ur,Modify modify) { + if(dryRun) { + trans.info().printf("Would Update %s %s", ur.user(), ur.role()); + return Result.ok(); + } else { + Result> rr = q.userRoleDAO.read(trans, ur.user(),ur.role()); + if(rr.notOKorIsEmpty()) { + return Result.err(rr); + } + for(Data d : rr.value) { + modify.change(d); + if(!(ur.expires().equals(d.expires))) { + ur.expires(d.expires); + } + if(ur.user().equals(d.user) && ur.role().equals(d.role)){ + Result rv = q.userRoleDAO.update(trans, d); + if(rv.isOK()) { + trans.info().printf("Updated %s %s to %s", ur.user(), ur.role(), d.toString()); + } else { + trans.info().log(rv.errorString()); + } + } else { + return Result.err(Status.ERR_Denied, "You cannot change the key of this Data"); + } + } + return Result.err(Status.ERR_UserRoleNotFound,"No User Role with %s %s",ur.user(),ur.role()); + } + } + + public static interface Modify { + void change(UserRoleDAO.Data ur); + } + +} \ No newline at end of file diff --git a/auth/auth-batch/src/main/java/org/onap/aaf/auth/actions/URPrint.java b/auth/auth-batch/src/main/java/org/onap/aaf/auth/actions/URPrint.java new file mode 100644 index 00000000..a9bdf9ca --- /dev/null +++ b/auth/auth-batch/src/main/java/org/onap/aaf/auth/actions/URPrint.java @@ -0,0 +1,42 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.actions; + +import org.onap.aaf.auth.env.AuthzTrans; +import org.onap.aaf.auth.helpers.UserRole; +import org.onap.aaf.auth.layer.Result; +import org.onap.aaf.misc.env.util.Chrono; + +public class URPrint implements Action { + private String info; + + public URPrint(String text) { + this.info = text; + } + + @Override + public Result exec(AuthzTrans trans, UserRole ur, String text) { + trans.info().log(info,text,ur.user(),"to",ur.role(),"expiring on",Chrono.dateOnlyStamp(ur.expires())); + return Result.ok(); + } + +} \ No newline at end of file diff --git a/auth/auth-batch/src/main/java/org/onap/aaf/auth/actions/URPunt.java b/auth/auth-batch/src/main/java/org/onap/aaf/auth/actions/URPunt.java new file mode 100644 index 00000000..8676ef33 --- /dev/null +++ b/auth/auth-batch/src/main/java/org/onap/aaf/auth/actions/URPunt.java @@ -0,0 +1,70 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.actions; + +import java.io.IOException; +import java.util.Date; +import java.util.List; + +import org.onap.aaf.auth.dao.cass.UserRoleDAO; +import org.onap.aaf.auth.dao.cass.UserRoleDAO.Data; +import org.onap.aaf.auth.env.AuthzTrans; +import org.onap.aaf.auth.helpers.UserRole; +import org.onap.aaf.auth.layer.Result; +import org.onap.aaf.misc.env.APIException; +import org.onap.aaf.misc.env.util.Chrono; + +import com.datastax.driver.core.Cluster; + +public class URPunt extends ActionPuntDAO { + public URPunt(AuthzTrans trans, Cluster cluster, int months, int range, boolean dryRun) throws APIException, IOException { + super(trans,cluster, months, range,dryRun); + } + + public URPunt(AuthzTrans trans, ActionDAO adao, int months, int range) { + super(trans, adao, months, range); + } + + public Result exec(AuthzTrans trans, UserRole ur, String text) { + if(dryRun) { + trans.info().log("Would Update User",ur.user(),"and Role", ur.role(), text); + return Result.ok(); + } else { + Result> read = q.userRoleDAO.read(trans, ur.user(), ur.role()); + if(read.isOK()) { + for(UserRoleDAO.Data data : read.value) { + Date from = data.expires; + data.expires = puntDate(from); + if(data.expires.compareTo(from)<=0) { + trans.debug().printf("Error: %s is same or before %s", Chrono.dateOnlyStamp(data.expires), Chrono.dateOnlyStamp(from)); + } else { + trans.info().log("Updating User",ur.user(),"and Role", ur.role(), "from",Chrono.dateOnlyStamp(from),"to",Chrono.dateOnlyStamp(data.expires), text); + q.userRoleDAO.update(trans, data); + } + } + return Result.ok(); + } else { + return Result.err(read); + } + } + } +} \ No newline at end of file diff --git a/auth/auth-batch/src/main/java/org/onap/aaf/auth/entryConverters/AafEntryConverter.java b/auth/auth-batch/src/main/java/org/onap/aaf/auth/entryConverters/AafEntryConverter.java new file mode 100644 index 00000000..637ee569 --- /dev/null +++ b/auth/auth-batch/src/main/java/org/onap/aaf/auth/entryConverters/AafEntryConverter.java @@ -0,0 +1,46 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.entryConverters; + +import java.util.Set; + +public abstract class AafEntryConverter { + + protected String formatSet(Set set) { + if (set==null || set.isEmpty()) return ""; + StringBuilder sb = new StringBuilder(); + int curr = 0; + sb.append("{"); + for (String s : set) { + sb.append("'"); + sb.append(s); + sb.append("'"); + if (set.size() != curr + 1) { + sb.append(","); + } + curr++; + } + sb.append("}"); + return sb.toString(); + } + +} diff --git a/auth/auth-batch/src/main/java/org/onap/aaf/auth/entryConverters/CredEntryConverter.java b/auth/auth-batch/src/main/java/org/onap/aaf/auth/entryConverters/CredEntryConverter.java new file mode 100644 index 00000000..6153e75e --- /dev/null +++ b/auth/auth-batch/src/main/java/org/onap/aaf/auth/entryConverters/CredEntryConverter.java @@ -0,0 +1,48 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.entryConverters; + +import java.text.DateFormat; +import java.text.SimpleDateFormat; + +import org.onap.aaf.auth.dao.cass.CredDAO; + +import com.datastax.driver.core.utils.Bytes; +import com.googlecode.jcsv.writer.CSVEntryConverter; + +public class CredEntryConverter extends AafEntryConverter implements CSVEntryConverter { + private static final String DATE_FORMAT = "yyyy-MM-dd HH:mm:ssZ"; + + @Override + public String[] convertEntry(CredDAO.Data cd) { + String[] columns = new String[5]; + + columns[0] = cd.id; + columns[1] = String.valueOf(cd.type); + DateFormat df = new SimpleDateFormat(DATE_FORMAT); + columns[2] = df.format(cd.expires); + columns[3] = Bytes.toHexString(cd.cred); + columns[4] = (cd.ns==null)?"":cd.ns; + + return columns; + } +} diff --git a/auth/auth-batch/src/main/java/org/onap/aaf/auth/entryConverters/NsEntryConverter.java b/auth/auth-batch/src/main/java/org/onap/aaf/auth/entryConverters/NsEntryConverter.java new file mode 100644 index 00000000..b2767ab4 --- /dev/null +++ b/auth/auth-batch/src/main/java/org/onap/aaf/auth/entryConverters/NsEntryConverter.java @@ -0,0 +1,46 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.entryConverters; + +import org.onap.aaf.auth.dao.cass.NsDAO; + +import com.googlecode.jcsv.writer.CSVEntryConverter; + +public class NsEntryConverter extends AafEntryConverter implements CSVEntryConverter { + + @Override + public String[] convertEntry(NsDAO.Data nsd) { + String[] columns = new String[5]; + + columns[0] = nsd.name; + // Jonathan changed from "scope" to "type" + columns[1] = String.valueOf(nsd.type); + //TODO Chris: need to look at this +// columns[2] = formatSet(nsd.admin); +// columns[3] = formatSet(nsd.responsible); +// columns[4] = nsd.description==null?"":nsd.description; + columns[5] = nsd.description==null?"":nsd.description; + + return columns; + } + +} diff --git a/auth/auth-batch/src/main/java/org/onap/aaf/auth/entryConverters/PermEntryConverter.java b/auth/auth-batch/src/main/java/org/onap/aaf/auth/entryConverters/PermEntryConverter.java new file mode 100644 index 00000000..12995f68 --- /dev/null +++ b/auth/auth-batch/src/main/java/org/onap/aaf/auth/entryConverters/PermEntryConverter.java @@ -0,0 +1,43 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.entryConverters; + +import org.onap.aaf.auth.dao.cass.PermDAO; + +import com.googlecode.jcsv.writer.CSVEntryConverter; + +public class PermEntryConverter extends AafEntryConverter implements CSVEntryConverter { + + @Override + public String[] convertEntry(PermDAO.Data pd) { + String[] columns = new String[6]; + + columns[0] = pd.ns; + columns[1] = pd.type; + columns[2] = pd.instance; + columns[3] = pd.action; + columns[4] = formatSet(pd.roles); + columns[5] = pd.description==null?"":pd.description; + + return columns; + } +} diff --git a/auth/auth-batch/src/main/java/org/onap/aaf/auth/entryConverters/RoleEntryConverter.java b/auth/auth-batch/src/main/java/org/onap/aaf/auth/entryConverters/RoleEntryConverter.java new file mode 100644 index 00000000..e236f3c3 --- /dev/null +++ b/auth/auth-batch/src/main/java/org/onap/aaf/auth/entryConverters/RoleEntryConverter.java @@ -0,0 +1,42 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.entryConverters; + +import org.onap.aaf.auth.dao.cass.RoleDAO; + +import com.googlecode.jcsv.writer.CSVEntryConverter; + +public class RoleEntryConverter extends AafEntryConverter implements CSVEntryConverter { + + @Override + public String[] convertEntry(RoleDAO.Data rd) { + String[] columns = new String[4]; + + columns[0] = rd.ns; + columns[1] = rd.name; + columns[2] = formatSet(rd.perms); + columns[3] = rd.description==null?"":rd.description; + + return columns; + } + +} diff --git a/auth/auth-batch/src/main/java/org/onap/aaf/auth/entryConverters/UserRoleEntryConverter.java b/auth/auth-batch/src/main/java/org/onap/aaf/auth/entryConverters/UserRoleEntryConverter.java new file mode 100644 index 00000000..8730f945 --- /dev/null +++ b/auth/auth-batch/src/main/java/org/onap/aaf/auth/entryConverters/UserRoleEntryConverter.java @@ -0,0 +1,45 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.entryConverters; + +import java.text.DateFormat; +import java.text.SimpleDateFormat; + +import org.onap.aaf.auth.dao.cass.UserRoleDAO; + +import com.googlecode.jcsv.writer.CSVEntryConverter; + +public class UserRoleEntryConverter extends AafEntryConverter implements CSVEntryConverter { + private static final String DATE_FORMAT = "yyyy-MM-dd HH:mm:ssZ"; + + @Override + public String[] convertEntry(UserRoleDAO.Data urd) { + String[] columns = new String[3]; + + columns[0] = urd.user; + columns[1] = urd.role; + DateFormat df = new SimpleDateFormat(DATE_FORMAT); + columns[2] = df.format(urd.expires); + + return columns; + } +} diff --git a/auth/auth-batch/src/main/java/org/onap/aaf/auth/helpers/Approval.java b/auth/auth-batch/src/main/java/org/onap/aaf/auth/helpers/Approval.java new file mode 100644 index 00000000..0bd9397c --- /dev/null +++ b/auth/auth-batch/src/main/java/org/onap/aaf/auth/helpers/Approval.java @@ -0,0 +1,309 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.helpers; + +import java.util.ArrayList; +import java.util.Date; +import java.util.List; +import java.util.TreeMap; +import java.util.UUID; + +import org.onap.aaf.auth.dao.cass.ApprovalDAO; +import org.onap.aaf.auth.env.AuthzTrans; +import org.onap.aaf.auth.layer.Result; +import org.onap.aaf.misc.env.Env; +import org.onap.aaf.misc.env.TimeTaken; +import org.onap.aaf.misc.env.Trans; + +import com.datastax.driver.core.ResultSet; +import com.datastax.driver.core.Row; +import com.datastax.driver.core.Session; +import com.datastax.driver.core.SimpleStatement; +import com.datastax.driver.core.Statement; + +public class Approval implements CacheChange.Data { + public static final String RE_APPROVAL_IN_ROLE = "Re-Approval in Role '"; + public static final String RE_VALIDATE_ADMIN = "Re-Validate as Administrator for AAF Namespace '"; + public static final String RE_VALIDATE_OWNER = "Re-Validate Ownership for AAF Namespace '"; + + public static TreeMap> byApprover = new TreeMap>(); + public static TreeMap> byUser = new TreeMap>(); + public static TreeMap> byTicket = new TreeMap>(); + private final static CacheChange cache = new CacheChange(); + + public final ApprovalDAO.Data add; + private String role; + + public Approval(UUID id, UUID ticket, String approver, Date last_notified, + String user, String memo, String operation, String status, String type, long updated) { + add = new ApprovalDAO.Data(); + add.id = id; + add.ticket = ticket; + add.approver = approver; + add.last_notified = last_notified; + add.user = user; + add.memo = memo; + add.operation = operation; + add.status = status; + add.type = type; + add.updated = new Date(updated); + role = roleFromMemo(memo); + } + + public static String roleFromMemo(String memo) { + if(memo==null) { + return null; + } + int first = memo.indexOf('\''); + if(first>=0) { + int second = memo.indexOf('\'', ++first); + if(second>=0) { + String role = memo.substring(first, second); + if(memo.startsWith(RE_VALIDATE_ADMIN)) { + return role + ".admin"; + } else if(memo.startsWith(RE_VALIDATE_OWNER)) { + return role + ".owner"; + } else if(memo.startsWith(RE_APPROVAL_IN_ROLE)) { + return role; + } + } + } + return null; + } + + public static void load(Trans trans, Session session, Creator creator ) { + trans.info().log( "query: " + creator.select() ); + TimeTaken tt = trans.start("Load Notify", Env.REMOTE); + + ResultSet results; + try { + Statement stmt = new SimpleStatement(creator.select()); + results = session.execute(stmt); + } finally { + tt.done(); + } + int count = 0; + tt = trans.start("Process Notify", Env.SUB); + + try { + List ln; + for(Row row : results.all()) { + ++count; + try { + Approval app = creator.create(row); + String person = app.getApprover(); + if(person!=null) { + ln = byApprover.get(person); + if(ln==null) { + ln = new ArrayList(); + byApprover.put(app.getApprover(), ln); + } + ln.add(app); + } + + + person = app.getUser(); + if(person!=null) { + ln = byUser.get(person); + if(ln==null) { + ln = new ArrayList(); + byUser.put(app.getUser(), ln); + } + ln.add(app); + } + UUID ticket = app.getTicket(); + if(ticket!=null) { + ln = byTicket.get(ticket); + if(ln==null) { + ln = new ArrayList(); + byTicket.put(app.getTicket(), ln); + } + ln.add(app); + } + } finally { + tt.done(); + } + } + } finally { + tt.done(); + trans.info().log("Found",count,"Approval Records"); + } + } + + @Override + public void expunge() { + List la = byApprover.get(getApprover()); + if(la!=null) { + la.remove(this); + } + + la = byUser.get(getUser()); + if(la!=null) { + la.remove(this); + } + UUID ticket = this.add==null?null:this.add.ticket; + if(ticket!=null) { + la = byTicket.get(this.add.ticket); + if(la!=null) { + la.remove(this); + } + } + } + + public void update(AuthzTrans trans, ApprovalDAO apprDAO, boolean dryRun) { + if(dryRun) { + trans.info().printf("Would update Approval %s, %s, last_notified %s",add.id,add.status,add.last_notified); + } else { + trans.info().printf("Update Approval %s, %s, last_notified %s",add.id,add.status,add.last_notified); + apprDAO.update(trans, add); + } + } + + public static Creator v2_0_17 = new Creator() { + @Override + public Approval create(Row row) { + return new Approval(row.getUUID(0), row.getUUID(1), row.getString(2), row.getTimestamp(3), + row.getString(4),row.getString(5),row.getString(6),row.getString(7),row.getString(8) + ,row.getLong(9)/1000); + } + + @Override + public String select() { + return "select id,ticket,approver,last_notified,user,memo,operation,status,type,WRITETIME(status) from authz.approval"; + } + }; + + /** + * @return the lastNotified + */ + public Date getLast_notified() { + return add.last_notified; + } + /** + * @param lastNotified the lastNotified to set + */ + public void setLastNotified(Date last_notified) { + add.last_notified = last_notified; + } + /** + * @return the status + */ + public String getStatus() { + return add.status; + } + /** + * @param status the status to set + */ + public void setStatus(String status) { + add.status = status; + } + /** + * @return the id + */ + public UUID getId() { + return add.id; + } + /** + * @return the ticket + */ + public UUID getTicket() { + return add.ticket; + } + /** + * @return the approver + */ + public String getApprover() { + return add.approver; + } + /** + * @return the user + */ + public String getUser() { + return add.user; + } + /** + * @return the memo + */ + public String getMemo() { + return add.memo; + } + /** + * @return the operation + */ + public String getOperation() { + return add.operation; + } + /** + * @return the type + */ + public String getType() { + return add.type; + } + public void lapsed() { + add.ticket=null; + add.status="lapsed"; + } + + public String getRole() { + return role; + } + + public String toString() { + return getUser() + ' ' + getMemo(); + } + + public void delayDelete(AuthzTrans trans, ApprovalDAO ad, boolean dryRun, String text) { + if(dryRun) { + trans.info().log(text,"- Would Delete: Approval",getId(),"on ticket",getTicket(),"for",getApprover()); + } else { + Result rv = ad.delete(trans, add, false); + if(rv.isOK()) { + trans.info().log(text,"- Deleted: Approval",getId(),"on ticket",getTicket(),"for",getApprover()); + cache.delayedDelete(this); + } else { + trans.info().log(text,"- Failed to Delete Approval",getId()); + } + } + } + + + public static void resetLocalData() { + cache.resetLocalData(); + } + + public static int sizeForDeletion() { + return cache.cacheSize(); + } + + public static void delayDelete(AuthzTrans noAvg, ApprovalDAO apprDAO, boolean dryRun, List list, String text) { + if(list!=null) { + for(Approval a : list) { + a.delayDelete(noAvg, apprDAO, dryRun,text); + } + } + } + + public static boolean pendingDelete(Approval a) { + return cache.contains(a); + } + +} diff --git a/auth/auth-batch/src/main/java/org/onap/aaf/auth/helpers/Approver.java b/auth/auth-batch/src/main/java/org/onap/aaf/auth/helpers/Approver.java new file mode 100644 index 00000000..6043e436 --- /dev/null +++ b/auth/auth-batch/src/main/java/org/onap/aaf/auth/helpers/Approver.java @@ -0,0 +1,62 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.helpers; + +import java.util.HashMap; +import java.util.Map; + +import org.onap.aaf.auth.actions.Message; +import org.onap.aaf.auth.org.Organization; + +public class Approver { + public String name; + public Organization org; + public Map userRequests; + + public Approver(String approver, Organization org) { + this.name = approver; + this.org = org; + userRequests = new HashMap(); + } + + public void addRequest(String user) { + if (userRequests.get(user) == null) { + userRequests.put(user, 1); + } else { + Integer curCount = userRequests.remove(user); + userRequests.put(user, curCount+1); + } + } + + /** + * @param sb + * @return + */ + public void build(Message msg) { + msg.clear(); + msg.line("You have %d total pending approvals from the following users:", userRequests.size()); + for (Map.Entry entry : userRequests.entrySet()) { + msg.line(" %s (%d)",entry.getKey(),entry.getValue()); + } + } + +} diff --git a/auth/auth-batch/src/main/java/org/onap/aaf/auth/helpers/CacheChange.java b/auth/auth-batch/src/main/java/org/onap/aaf/auth/helpers/CacheChange.java new file mode 100644 index 00000000..02f34d28 --- /dev/null +++ b/auth/auth-batch/src/main/java/org/onap/aaf/auth/helpers/CacheChange.java @@ -0,0 +1,63 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.helpers; + +import java.util.ArrayList; +import java.util.List; + +public class CacheChange { + private List removed; + + public CacheChange() { + removed = new ArrayList(); + } + + interface Data { + public abstract void expunge(); + } + + public final void delayedDelete(T t) { + removed.add(t); + } + + public final List getRemoved() { + return removed; + } + + public final void resetLocalData() { + if(removed==null || removed.isEmpty()) { + return; + } + for(T t : removed) { + t.expunge(); + } + removed.clear(); + } + + public int cacheSize() { + return removed.size(); + } + + public boolean contains(T t) { + return removed.contains(t); + } +} diff --git a/auth/auth-batch/src/main/java/org/onap/aaf/auth/helpers/Creator.java b/auth/auth-batch/src/main/java/org/onap/aaf/auth/helpers/Creator.java new file mode 100644 index 00000000..da6d558c --- /dev/null +++ b/auth/auth-batch/src/main/java/org/onap/aaf/auth/helpers/Creator.java @@ -0,0 +1,41 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.helpers; + +import com.datastax.driver.core.Row; + +public abstract class Creator { + public abstract T create(Row row); + public abstract String select(); + + public String query(String where) { + StringBuilder sb = new StringBuilder(select()); + if(where!=null) { + sb.append(" WHERE "); + sb.append(where); + } + sb.append(';'); + return sb.toString(); + } + + +} \ No newline at end of file diff --git a/auth/auth-batch/src/main/java/org/onap/aaf/auth/helpers/Cred.java b/auth/auth-batch/src/main/java/org/onap/aaf/auth/helpers/Cred.java new file mode 100644 index 00000000..58af03b5 --- /dev/null +++ b/auth/auth-batch/src/main/java/org/onap/aaf/auth/helpers/Cred.java @@ -0,0 +1,306 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.helpers; + +import java.util.ArrayList; +import java.util.Date; +import java.util.GregorianCalendar; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Set; +import java.util.TreeMap; + +import org.onap.aaf.auth.dao.cass.CredDAO; +import org.onap.aaf.auth.dao.hl.Question; +import org.onap.aaf.misc.env.Env; +import org.onap.aaf.misc.env.TimeTaken; +import org.onap.aaf.misc.env.Trans; + +import com.datastax.driver.core.ResultSet; +import com.datastax.driver.core.Row; +import com.datastax.driver.core.Session; +import com.datastax.driver.core.SimpleStatement; +import com.datastax.driver.core.Statement; + +public class Cred { + public static final TreeMap data = new TreeMap(); + public static final TreeMap> byNS = new TreeMap>(); + + public final String id; + public final List instances; + public final String ns; + + public Cred(String id) { + this.id = id; + instances = new ArrayList(); + ns=Question.domain2ns(id); + } + + public static class Instance { + public final int type; + public final Date expires,written; + public final Integer other; + + public Instance(int type, Date expires, Integer other, long written) { + this.type = type; + this.expires = expires; + this.other = other; + this.written = new Date(written); + } + } + + public Date last(final int ... types) { + Date last = null; + for(Instance i : instances) { + if(types.length>0) { // filter by types, if requested + boolean quit = true; + for(int t : types) { + if(t==i.type) { + quit=false; + break; + } + } + if(quit) { + continue; + } + } + if(last==null || i.expires.after(last)) { + last = i.expires; + } + } + return last; + } + + + public Set types() { + Set types = new HashSet(); + for(Instance i : instances) { + types.add(i.type); + } + return types; + } + + public static void load(Trans trans, Session session, int ... types ) { + load(trans, session,"select id, type, expires, other, writetime(cred) from authz.cred;",types); + + } + + public static void loadOneNS(Trans trans, Session session, String ns,int ... types ) { + load(trans, session,"select id, type, expires, other, writetime(cred) from authz.cred WHERE ns='" + ns + "';"); + } + + private static void load(Trans trans, Session session, String query, int ...types) { + + trans.info().log( "query: " + query ); + TimeTaken tt = trans.start("Read Creds", Env.REMOTE); + + ResultSet results; + try { + Statement stmt = new SimpleStatement( query ); + results = session.execute(stmt); + } finally { + tt.done(); + } + int count = 0; + try { + Iterator iter = results.iterator(); + Row row; + int type; // for filtering + String id; + tt = trans.start("Load Credentials", Env.SUB); + try { + while(iter.hasNext()) { + ++count; + row = iter.next(); + id = row.getString(0); + type = row.getInt(1); + if(types.length>0) { // filter by types, if requested + boolean quit = true; + for(int t : types) { + if(t==type) { + quit=false; + break; + } + } + if(quit) { + continue; + } + } + Cred cred = data.get(id); + if(cred==null) { + cred = new Cred(id); + data.put(id, cred); + } + cred.instances.add(new Instance(type, row.getTimestamp(2), row.getInt(3), row.getLong(4)/1000)); + + List lscd = byNS.get(cred.ns); + if(lscd==null) { + byNS.put(cred.ns, (lscd=new ArrayList())); + } + boolean found = false; + for(Cred c : lscd) { + if(c.id.equals(cred.id)) { + found=true; + break; + } + } + if(!found) { + lscd.add(cred); + } + } + } finally { + tt.done(); + } + } finally { + trans.info().log("Found",count,"creds"); + } + } + + /** + * Count entries in Cred data. + * Note, as opposed to other methods, need to load the whole cred table for the Types. + * @param numbuckets + * @return + */ + public static CredCount count(int numbuckets) { + CredCount cc = new CredCount(numbuckets); + for(Cred c : data.values()) { + for (Instance ci : c.instances) { + cc.inc(ci.type,ci.written, ci.expires); + } + } + return cc; +// String query = "select count(*) from authz.cred LIMIT 1000000;"; +// trans.info().log( "query: " + query ); +// TimeTaken tt = trans.start("Count Credentials", Env.REMOTE); +// ResultSet results; +// try { +// Statement stmt = new SimpleStatement(query).setReadTimeoutMillis(12000); +// results = session.execute(stmt); +// return results.one().getLong(0); +// } finally { +// tt.done(); +// } + } + + public static class CredCount { + public int raw[]; + public int basic_auth[]; + public int basic_auth_256[]; + public int cert[]; + public int x509Added[]; + public int x509Expired[]; + public Date dates[]; + + public CredCount(int numbuckets) { + raw = new int[numbuckets]; + basic_auth = new int[numbuckets]; + basic_auth_256 = new int[numbuckets]; + cert = new int[numbuckets]; + x509Added = new int[numbuckets]; + x509Expired = new int[numbuckets]; + dates = new Date[numbuckets]; + GregorianCalendar gc = new GregorianCalendar(); + dates[0]=gc.getTime(); // now + gc.set(GregorianCalendar.DAY_OF_MONTH, 1); + gc.set(GregorianCalendar.HOUR, 0); + gc.set(GregorianCalendar.MINUTE, 0); + gc.set(GregorianCalendar.SECOND,0); + gc.set(GregorianCalendar.MILLISECOND,0); + gc.add(GregorianCalendar.MILLISECOND, -1); // last milli of month + for(int i=1;i { + public static final Map data = new TreeMap(); + public static final Map> byRole = new TreeMap>(); + + public final FutureDAO.Data fdd; + public final String role; // derived + private final static CacheChange cache = new CacheChange(); + + + public final UUID id() { + return fdd.id; + } + + public final String memo() { + return fdd.memo; + } + + public final String target() { + return fdd.target; + } + + public final Date start() { + return fdd.start; + } + + public final Date expires() { + return fdd.expires; + } + + + public Future(UUID id, String memo, String target, Date start, Date expires, ByteBuffer construct) { + fdd = new FutureDAO.Data(); + fdd.id = id; + fdd.memo = memo; + fdd.target = target; + fdd.start = start; + fdd.expires = expires; + fdd.construct = construct; + role = Approval.roleFromMemo(memo); + } + + public static void load(Trans trans, Session session, Creator creator) { + trans.info().log( "query: " + creator.select() ); + ResultSet results; + TimeTaken tt = trans.start("Load Futures", Env.REMOTE); + try { + Statement stmt = new SimpleStatement(creator.select()); + results = session.execute(stmt); + } finally { + tt.done(); + } + + int count = 0; + tt = trans.start("Process Futures", Env.SUB); + try { + for(Row row : results.all()) { + ++count; + Future f = creator.create(row); + data.put(f.fdd.id,f); + if(f.role!=null) { + List lf = byRole.get(f.role); + if(lf==null) { + byRole.put(f.role,lf = new ArrayList()); + } + lf.add(f); + } + } + } finally { + tt.done(); + trans.info().log("Found",count,"Futures"); + } + } + + public static Creator v2_0_17 = new Creator() { + @Override + public Future create(Row row) { + return new Future(row.getUUID(0),row.getString(1),row.getString(2), + row.getTimestamp(3),row.getTimestamp(4), null); + } + + @Override + public String select() { + return "select id,memo,target,start,expires from authz.future"; + } + }; + + public static Creator withConstruct = new Creator() { + @Override + public String select() { + return "select id,memo,target,start,expires,construct from authz.future"; + } + + @Override + public Future create(Row row) { + return new Future(row.getUUID(0),row.getString(1),row.getString(2), + row.getTimestamp(3),row.getTimestamp(4), row.getBytes(5)); + } + + }; + + public Result delayedDelete(AuthzTrans trans, FutureDAO fd, boolean dryRun, String text) { + Result rv; + if(dryRun) { + trans.info().log(text,"- Would Delete: ",fdd.id,fdd.memo,"expiring on",Chrono.dateOnlyStamp(fdd.expires)); + rv = Result.ok(); + } else { + rv = fd.delete(trans, fdd, true); // need to read for undelete + if(rv.isOK()) { + trans.info().log(text, "- Deleted:",fdd.id,fdd.memo,"expiring on",Chrono.dateOnlyStamp(fdd.expires)); + cache.delayedDelete(this); + } else { + if(rv.status!=6) { + trans.info().log(text,"- Failed to Delete Future", fdd.id); + } + } + } + return rv; + } + + /* (non-Javadoc) + * @see org.onap.aaf.auth.helpers.CacheChange.Data#resetLocalData() + */ + @Override + public void expunge() { + data.remove(fdd.id); + if(role!=null) { + List lf = byRole.get(role); + if(lf!=null) { + lf.remove(this); + } + } + } + + @Override + public int compareTo(Future o) { + if(o==null) { + return -1; + } + return fdd.id.compareTo(o.fdd.id); + } + + public static void resetLocalData() { + cache.resetLocalData(); + } + + public static int sizeForDeletion() { + return cache.cacheSize(); + } + + public static boolean pendingDelete(Future f) { + return cache.contains(f); + } + + +} diff --git a/auth/auth-batch/src/main/java/org/onap/aaf/auth/helpers/History.java b/auth/auth-batch/src/main/java/org/onap/aaf/auth/helpers/History.java new file mode 100644 index 00000000..f153c06b --- /dev/null +++ b/auth/auth-batch/src/main/java/org/onap/aaf/auth/helpers/History.java @@ -0,0 +1,178 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.helpers; + +import java.nio.ByteBuffer; +import java.util.Iterator; +import java.util.UUID; + +import org.onap.aaf.misc.env.Env; +import org.onap.aaf.misc.env.TimeTaken; +import org.onap.aaf.misc.env.Trans; + +import com.datastax.driver.core.ResultSet; +import com.datastax.driver.core.Row; +import com.datastax.driver.core.Session; +import com.datastax.driver.core.SimpleStatement; +import com.datastax.driver.core.Statement; + +public class History { + public final UUID id; + public final String action; + public final String memo; + public final String reconstruct; + public final String subject; + public final String target; + public final String user; + public final int yr_mon; + + public History(UUID id, String action, String memo, String subject, String target, String user, int yr_mon) { + this.id = id; + this.action = action; + this.memo = memo; + this.reconstruct = null; + this.subject = subject; + this.target = target; + this.user = user; + this.yr_mon = yr_mon; + } + + public History(UUID id, String action, String memo, String reconstruct, String subject, String target, String user, int yr_mon) { + this.id = id; + this.action = action; + this.memo = memo; + this.reconstruct = reconstruct; + this.subject = subject; + this.target = target; + this.user = user; + this.yr_mon = yr_mon; + } + + public static void load(Trans trans, Session session, Creator creator, Loader loader) { + trans.info().log( "query: " + creator.select() ); + TimeTaken tt = trans.start("Read History", Env.REMOTE); + + ResultSet results; + try { + Statement stmt = new SimpleStatement( creator.select() ).setReadTimeoutMillis(240000); + results = session.execute(stmt); + } finally { + tt.done(); + } + int count = 0; + try { + Iterator iter = results.iterator(); + Row row; + tt = trans.start("Load History", Env.SUB); + try { + while(iter.hasNext()) { + ++count; + row = iter.next(); + loader.exec(creator.create(row)); + } + } finally { + tt.done(); + } + } finally { + trans.info().log("Found",count,"histories"); + } + } + + public String toString() { + return String.format("%s %d %s, %s, %s, %s, %s", + id.toString(), + yr_mon, + user, + target, + action, + subject, + memo); + } + + /* (non-Javadoc) + * @see java.lang.Object#hashCode() + */ + @Override + public int hashCode() { + return id.hashCode(); + } + + /* (non-Javadoc) + * @see java.lang.Object#equals(java.lang.Object) + */ + @Override + public boolean equals(Object obj) { + return id.equals(obj); + } + + public static Creator sansConstruct = new Creator () { + @Override + public History create(Row row) { + return new History( + row.getUUID(0), + row.getString(1), + row.getString(2), + row.getString(3), + row.getString(4), + row.getString(5), + row.getInt(6)); + } + + @Override + public String select() { + return "SELECT id, action, memo, subject, target, user, yr_mon from authz.history LIMIT 10000000 "; + } + }; + + public static Creator avecConstruct = new Creator () { + private final StringBuilder sb = new StringBuilder(); + + @Override + public History create(Row row) { + ByteBuffer bb = row.getBytes(3); + sb.setLength(0); + + if(bb!=null && bb.hasRemaining()) { + sb.append("0x"); + while(bb.hasRemaining()) { + sb.append(String.format("%02x",bb.get())); + } + bb.flip(); + } + return new History( + row.getUUID(0), + row.getString(1), + row.getString(2), + sb.toString(), + row.getString(4), + row.getString(5), + row.getString(6), + row.getInt(7)); + } + + @Override + public String select() { + return "SELECT id, action, memo, reconstruct, subject, target, user, yr_mon from authz.history LIMIT 10000000 "; + } + }; + +} \ No newline at end of file diff --git a/auth/auth-batch/src/main/java/org/onap/aaf/auth/helpers/InputIterator.java b/auth/auth-batch/src/main/java/org/onap/aaf/auth/helpers/InputIterator.java new file mode 100644 index 00000000..cb0bfa6a --- /dev/null +++ b/auth/auth-batch/src/main/java/org/onap/aaf/auth/helpers/InputIterator.java @@ -0,0 +1,69 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.helpers; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.PrintStream; +import java.util.Iterator; + +public class InputIterator implements Iterable { + private BufferedReader in; + private final PrintStream out; + private final String prompt, instructions; + + public InputIterator(BufferedReader in, PrintStream out, String prompt, String instructions) { + this.in = in; + this.out = out; + this.prompt = prompt; + this.instructions = instructions; + } + + @Override + public Iterator iterator() { + out.println(instructions); + return new Iterator() { + String input; + @Override + public boolean hasNext() { + out.append(prompt); + try { + input = in.readLine(); + } catch (IOException e) { + input = null; + return false; + } + return input.length()>0; + } + + @Override + public String next() { + return input; + } + + @Override + public void remove() { + } + }; + } +} + diff --git a/auth/auth-batch/src/main/java/org/onap/aaf/auth/helpers/Loader.java b/auth/auth-batch/src/main/java/org/onap/aaf/auth/helpers/Loader.java new file mode 100644 index 00000000..6d27f648 --- /dev/null +++ b/auth/auth-batch/src/main/java/org/onap/aaf/auth/helpers/Loader.java @@ -0,0 +1,26 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.helpers; + +public interface Loader { + public void exec(T t); +} \ No newline at end of file diff --git a/auth/auth-batch/src/main/java/org/onap/aaf/auth/helpers/MiscID.java b/auth/auth-batch/src/main/java/org/onap/aaf/auth/helpers/MiscID.java new file mode 100644 index 00000000..1438ffdb --- /dev/null +++ b/auth/auth-batch/src/main/java/org/onap/aaf/auth/helpers/MiscID.java @@ -0,0 +1,188 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.helpers; + +import java.util.Map; +import java.util.TreeMap; + +import org.onap.aaf.auth.BatchException; +import org.onap.aaf.misc.env.Env; +import org.onap.aaf.misc.env.TimeTaken; +import org.onap.aaf.misc.env.Trans; + +import com.datastax.driver.core.ResultSet; +import com.datastax.driver.core.Row; +import com.datastax.driver.core.Session; +import com.datastax.driver.core.SimpleStatement; +import com.datastax.driver.core.Statement; + +public class MiscID { + public static final TreeMap data = new TreeMap(); + /* + Sample Record + aad890|mj9030|20040902|20120207 + + **** Field Definitions **** + MISCID - AT&T Miscellaneous ID - Non-User ID (Types: Internal Mechanized ID, External Mechanized ID, Datagate ID, Customer ID, Vendor ID, Exchange Mail ID, CLEC ID, Specialized ID, Training ID) + SPONSOR_ATTUID - ATTUID of MiscID Sponsor (Owner) + CREATE_DATE - Date when MiscID was created + LAST_RENEWAL_DATE - Date when MiscID Sponsorship was last renewed + */ + public String id,sponsor,created,renewal; + + private static final String fieldString = "id,created,sponsor,renewal"; + + /** + * Load a Row of Strings (from CSV file). + * + * Be CAREFUL that the Row lists match the Fields above!!! If this changes, change + * 1) This Object + * 2) DB "suits.cql" + * 3) Alter existing Tables + * @param row + * @throws BatchException + * @throws IllegalAccessException + * @throws IllegalArgumentException + */ + public void set(String row []) throws BatchException { + if(row.length<4) {throw new BatchException("Row of MiscID_XRef is too short");} + id = row[0]; + sponsor = row[1]; + created = row[2]; + renewal = row[3]; + } + + public void set(Row row) { + id = row.getString(0); + sponsor = row.getString(1); + created = row.getString(2); + renewal = row.getString(3); + } + + + public static void load(Trans trans, Session session ) { + load(trans, session,"SELECT " + fieldString + " FROM authz.miscid;",data); + } + + public static void load(Trans trans, Session session, Map map ) { + load(trans, session,"SELECT " + fieldString + " FROM authz.miscid;",map); + } + + public static void loadOne(Trans trans, Session session, String id ) { + load(trans, session,"SELECT " + fieldString + " FROM authz.miscid WHERE id ='" + id + "';", data); + } + + public static void load(Trans trans, Session session, String query, Map map) { + trans.info().log( "query: " + query ); + TimeTaken tt = trans.start("Read MiscID", Env.REMOTE); + + ResultSet results; + try { + Statement stmt = new SimpleStatement( query ); + results = session.execute(stmt); + } finally { + tt.done(); + } + int count = 0; + try { + tt = trans.start("Load Map", Env.SUB); + try { + for( Row row : results.all()) { + MiscID miscID = new MiscID(); + miscID.set(row); + data.put(miscID.id,miscID); + ++count; + } + } finally { + tt.done(); + } + } finally { + trans.info().log("Found",count,"miscID records"); + } + } + + /* (non-Javadoc) + * @see java.lang.Object#hashCode() + */ + @Override + public int hashCode() { + return id.hashCode(); + } + + /* (non-Javadoc) + * @see java.lang.Object#equals(java.lang.Object) + */ + @Override + public boolean equals(Object obj) { + if(obj!=null && obj instanceof MiscID) { + return id.equals(((MiscID)obj).id); + } + return false; + } + + public StringBuilder insertStmt() throws IllegalArgumentException, IllegalAccessException { + StringBuilder sb = new StringBuilder("INSERT INTO authz.miscid ("); + sb.append(fieldString); + sb.append(") VALUES ('"); + sb.append(id); + sb.append("','"); + sb.append(sponsor); + sb.append("','"); + sb.append(created); + sb.append("','"); + sb.append(renewal); + sb.append("')"); + return sb; + } + + public StringBuilder updateStmt(MiscID source) { + StringBuilder sb = null; + if(id.equals(source.id)) { + sb = addField(sb,"sponser",sponsor,source.sponsor); + sb = addField(sb,"created",created,source.created); + sb = addField(sb,"renewal",renewal,source.renewal); + } + if(sb!=null) { + sb.append(" WHERE id='"); + sb.append(id); + sb.append('\''); + } + return sb; + } + + private StringBuilder addField(StringBuilder sb, String name, String a, String b) { + if(!a.equals(b)) { + if(sb==null) { + sb = new StringBuilder("UPDATE authz.miscid SET "); + } else { + sb.append(','); + } + sb.append(name); + sb.append("='"); + sb.append(b); + sb.append('\''); + } + return sb; + } + + +} \ No newline at end of file diff --git a/auth/auth-batch/src/main/java/org/onap/aaf/auth/helpers/MonthData.java b/auth/auth-batch/src/main/java/org/onap/aaf/auth/helpers/MonthData.java new file mode 100644 index 00000000..13a4c923 --- /dev/null +++ b/auth/auth-batch/src/main/java/org/onap/aaf/auth/helpers/MonthData.java @@ -0,0 +1,121 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.helpers; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileReader; +import java.io.IOException; +import java.io.PrintStream; +import java.util.HashSet; +import java.util.Map; +import java.util.Map.Entry; + +import org.onap.aaf.misc.env.util.Split; + +import java.util.Set; +import java.util.TreeMap; + +public class MonthData { + public final Map> data = + new TreeMap>(); + private File f; + + public MonthData(String env) throws IOException { + f = new File("Monthly"+env+".dat"); + + if(f.exists()) { + BufferedReader br = new BufferedReader(new FileReader(f)); + try { + String line; + String[] split; + while((line=br.readLine())!=null) { + if(!line.startsWith("#")) { + split = Split.split(',', line); + if(split.length==5) { + add(Integer.parseInt(split[0]),split[1], + Integer.parseInt(split[2]), + Integer.parseInt(split[3]), + Integer.parseInt(split[4]) + ); + } + } + } + } finally { + br.close(); + } + } + } + + public void add(int yr_mon, String target, long total, long adds, long drops) { + Set row = data.get(yr_mon); + if(row==null) { + data.put(yr_mon, (row=new HashSet())); + } + row.add(new Row(target,total,adds,drops)); + } + + public boolean notExists(int yr_mon) { + return data.get(yr_mon)==null; + } + + public static class Row implements Comparable { + public final String target; + public final long total; + public final long adds; + public final long drops; + + public Row(String t, long it, long a, long d) { + target = t; + total = it; + adds = a; + drops = d; + } + + @Override + public int compareTo(Row o) { + return target.compareTo(o.target); + } + + public String toString() { + return target + '|' + total + '|' + drops + '|' + adds; + } + } + + public void write() throws IOException { + if(f.exists()) { + File bu = new File(f.getName()+".bak"); + f.renameTo(bu); + } + PrintStream ps = new PrintStream(f); + try { + for( Entry> rows : data.entrySet()) { + for(Row row : rows.getValue()) { + ps.printf("%d,%s,%d,%d,%d\n",rows.getKey(),row.target,row.total,row.adds,row.drops); + } + } + } finally { + ps.close(); + } + } + +} diff --git a/auth/auth-batch/src/main/java/org/onap/aaf/auth/helpers/NS.java b/auth/auth-batch/src/main/java/org/onap/aaf/auth/helpers/NS.java new file mode 100644 index 00000000..5dde8895 --- /dev/null +++ b/auth/auth-batch/src/main/java/org/onap/aaf/auth/helpers/NS.java @@ -0,0 +1,168 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.helpers; + +import java.util.Iterator; +import java.util.Map; +import java.util.TreeMap; + +import org.onap.aaf.misc.env.Env; +import org.onap.aaf.misc.env.TimeTaken; +import org.onap.aaf.misc.env.Trans; + +import com.datastax.driver.core.ResultSet; +import com.datastax.driver.core.Row; +import com.datastax.driver.core.Session; +import com.datastax.driver.core.SimpleStatement; +import com.datastax.driver.core.Statement; + +public class NS implements Comparable { + public final static Map data = new TreeMap(); + + public final String name, description, parent; + public final int scope,type; + + public NS(String name, String description, String parent, int type, int scope) { + this.name = name; + this.description = description; + this.parent = parent; + this.scope = scope; + this.type = type; + } + + public static void load(Trans trans, Session session, Creator creator) { + load(trans,session, + "select name, description, parent, type, scope from authz.ns;" + ,creator); + } + + public static void loadOne(Trans trans, Session session, Creator creator, String ns) { + load(trans,session, + ("select name, description, parent, type, scope from authz.ns WHERE name='"+ns+"';") + ,creator + ); + } + + private static void load(Trans trans, Session session, String query, Creator creator) { + trans.info().log( "query: " + query ); + ResultSet results; + TimeTaken tt; + + tt = trans.start("Read Namespaces", Env.REMOTE); + try { + Statement stmt = new SimpleStatement( query ); + results = session.execute(stmt); + } finally { + tt.done(); + } + + + try { + Iterator iter = results.iterator(); + Row row; + tt = trans.start("Load Namespaces", Env.SUB); + try { + while(iter.hasNext()) { + row = iter.next(); + NS ns = creator.create(row); + data.put(ns.name,ns); + } + } finally { + tt.done(); + } + } finally { + trans.info().log("Found",data.size(),"Namespaces"); + } + + } + + public static long count(Trans trans, Session session) { + String query = "select count(*) from authz.ns LIMIT 1000000;"; + trans.info().log( "query: " + query ); + TimeTaken tt = trans.start("Count Namespaces", Env.REMOTE); + ResultSet results; + try { + Statement stmt = new SimpleStatement(query).setReadTimeoutMillis(12000); + results = session.execute(stmt); + return results.one().getLong(0); + } finally { + tt.done(); + } + } + + public String toString() { + return name; + } + + /* (non-Javadoc) + * @see java.lang.Object#hashCode() + */ + @Override + public int hashCode() { + return name.hashCode(); + } + + /* (non-Javadoc) + * @see java.lang.Object#equals(java.lang.Object) + */ + @Override + public boolean equals(Object obj) { + return name.equals(obj); + } + + @Override + public int compareTo(NS o) { + return name.compareTo(o.name); + } + + public static class NSSplit { + public String ns; + public String other; + public NSSplit(String s, int dot) { + ns = s.substring(0,dot); + other = s.substring(dot+1); + } + } + public static NSSplit deriveParent(String dotted) { + if(dotted==null)return null; + for(int idx = dotted.lastIndexOf('.');idx>=0; idx=dotted.lastIndexOf('.',idx-1)) { + if(data.get(dotted.substring(0, idx))!=null) { + return new NSSplit(dotted,idx); + } + } + return null; + } + + public static Creator v2_0_11 = new Creator () { + @Override + public NS create(Row row) { + return new NS(row.getString(0),row.getString(1), row.getString(2),row.getInt(3),row.getInt(4)); + } + + @Override + public String select() { + return "SELECT name, description, parent, type, scope FROM authz.ns "; + } + }; + + +} \ No newline at end of file diff --git a/auth/auth-batch/src/main/java/org/onap/aaf/auth/helpers/Notification.java b/auth/auth-batch/src/main/java/org/onap/aaf/auth/helpers/Notification.java new file mode 100644 index 00000000..9614bb19 --- /dev/null +++ b/auth/auth-batch/src/main/java/org/onap/aaf/auth/helpers/Notification.java @@ -0,0 +1,209 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.helpers; + +import java.util.ArrayList; +import java.util.Date; +import java.util.List; +import java.util.TreeMap; + +import org.onap.aaf.auth.actions.Message; +import org.onap.aaf.auth.env.AuthzTrans; +import org.onap.aaf.auth.org.Organization; +import org.onap.aaf.misc.env.Env; +import org.onap.aaf.misc.env.TimeTaken; +import org.onap.aaf.misc.env.Trans; +import org.onap.aaf.misc.env.util.Chrono; + +import com.datastax.driver.core.ResultSet; +import com.datastax.driver.core.Row; +import com.datastax.driver.core.Session; +import com.datastax.driver.core.SimpleStatement; +import com.datastax.driver.core.Statement; + +public class Notification { + public enum TYPE { + OA("Owner Approval",1),SA("Supervisor Approval",2),CN("Credential Expiration",20); + + private String desc; + private int type; + + private TYPE(String desc,int type) { + this.desc = desc; + this.type = type; + } + + public String desc() { + return desc; + } + + public int idx() { + return type; + } + + public static TYPE get(int idx) { + for(TYPE nt : TYPE.values()) { + if(idx==nt.type) { + return nt; + } + } + return null; + } + } + + + public static final TreeMap> data = new TreeMap>(); + public static final Date now = new Date(); + + public final String user; + public final TYPE type; + public Date last; + public int checksum; + public Message msg; + private int current; + public Organization org; + public int count; + + private Notification(String user, TYPE nt, Date last, int checksum) { + this.user = user; + this.type = nt; + this.last = last; + this.checksum = checksum; + current = 0; + count = 0; + } + + public static void load(Trans trans, Session session, Creator creator ) { + trans.info().log( "query: " + creator.select() ); + TimeTaken tt = trans.start("Load Notify", Env.REMOTE); + + ResultSet results; + try { + Statement stmt = new SimpleStatement(creator.select()); + results = session.execute(stmt); + } finally { + tt.done(); + } + int count = 0; + tt = trans.start("Process Notify", Env.SUB); + + try { + for(Row row : results.all()) { + ++count; + try { + Notification not = creator.create(row); + List ln = data.get(not.user); + if(ln==null) { + ln = new ArrayList(); + data.put(not.user, ln); + } + ln.add(not); + } finally { + tt.done(); + } + } + } finally { + tt.done(); + trans.info().log("Found",count,"Notify Records"); + } + } + + public static Notification get(String user, TYPE type) { + List ln = data.get(user); + if(ln!=null) { + for(Notification n : ln) { + if(type.equals(n.type)) { + return n; + } + } + } + return null; + } + + public static Notification create(String user, TYPE type) { + return new Notification(user,type,null,0); + } + + public static Creator v2_0_18 = new Creator() { + @Override + public Notification create(Row row) { + int idx =row.getInt(1); + TYPE type = TYPE.get(idx); + if(type==null) { + return null; + } + return new Notification(row.getString(0), type, row.getTimestamp(2), row.getInt(3)); + } + + @Override + public String select() { + return "SELECT user,type,last,checksum FROM authz.notify LIMIT 100000"; + } + }; + + + public void set(Message msg) { + this.msg = msg; + } + + public int checksum() { + if(msg==null) { + current=0; + } else if(current==0) { + for(String l : msg.lines) { + for(byte b : l.getBytes()) { + current+=b; + } + } + } + return current; + } + + public boolean update(AuthzTrans trans, Session session, boolean dryRun) { + checksum(); + if(last==null || current==0 || current!=checksum) { + last = now; + current = checksum(); + String update = "UPDATE authz.notify SET " + + "last = '" + Chrono.utcStamp(last) + + "', checksum=" + + current + + " WHERE user='" + + user + + "' AND type=" + + type.idx() + + ";"; + if(dryRun) { + trans.info().log("Would",update); + } else { + session.execute(update); + } + return true; + } + return false; + } + + public String toString() { + return "\"" + user + "\",\"" + type.name() + "\",\"" + + Chrono.dateTime(last)+ "\", " + checksum; + } +} \ No newline at end of file diff --git a/auth/auth-batch/src/main/java/org/onap/aaf/auth/helpers/NsAttrib.java b/auth/auth-batch/src/main/java/org/onap/aaf/auth/helpers/NsAttrib.java new file mode 100644 index 00000000..bb76c34c --- /dev/null +++ b/auth/auth-batch/src/main/java/org/onap/aaf/auth/helpers/NsAttrib.java @@ -0,0 +1,107 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.helpers; + +import java.util.ArrayList; +import java.util.List; +import java.util.TreeMap; + +import org.onap.aaf.misc.env.Env; +import org.onap.aaf.misc.env.TimeTaken; +import org.onap.aaf.misc.env.Trans; + +import com.datastax.driver.core.ResultSet; +import com.datastax.driver.core.Row; +import com.datastax.driver.core.Session; +import com.datastax.driver.core.SimpleStatement; +import com.datastax.driver.core.Statement; + +public class NsAttrib { + public static final List data = new ArrayList(); + public static final TreeMap> byKey = new TreeMap>(); + public static final TreeMap> byNS = new TreeMap>(); + + public final String ns,key,value; + + public NsAttrib(String ns, String key, String value) { + this.ns = ns; + this.key = key; + this.value = value; + } + + public static void load(Trans trans, Session session, Creator creator ) { + trans.info().log( "query: " + creator.select() ); + ResultSet results; + TimeTaken tt = trans.start("Load NsAttributes", Env.REMOTE); + try { + Statement stmt = new SimpleStatement(creator.select()); + results = session.execute(stmt); + } finally { + tt.done(); + } + int count = 0; + tt = trans.start("Process NsAttributes", Env.SUB); + + try { + for(Row row : results.all()) { + ++count; + NsAttrib ur = creator.create(row); + data.add(ur); + + List lna = byKey.get(ur.key); + if(lna==null) { + lna = new ArrayList(); + byKey.put(ur.key, lna); + } + lna.add(ur); + + lna = byNS.get(ur.ns); + if(lna==null) { + lna = new ArrayList(); + byNS.put(ur.ns, lna); + } + lna.add(ur); + } + } finally { + tt.done(); + trans.info().log("Found",count,"NS Attributes"); + } + } + + public static Creator v2_0_11 = new Creator() { + @Override + public NsAttrib create(Row row) { + return new NsAttrib(row.getString(0), row.getString(1), row.getString(2)); + } + + @Override + public String select() { + return "select ns,key,value from authz.ns_attrib"; + } + }; + + + public String toString() { + return '"' + ns + "\",\"" + key + "\",\"" + value +'"'; + } + +} \ No newline at end of file diff --git a/auth/auth-batch/src/main/java/org/onap/aaf/auth/helpers/Perm.java b/auth/auth-batch/src/main/java/org/onap/aaf/auth/helpers/Perm.java new file mode 100644 index 00000000..51a7098e --- /dev/null +++ b/auth/auth-batch/src/main/java/org/onap/aaf/auth/helpers/Perm.java @@ -0,0 +1,172 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.helpers; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.Set; +import java.util.TreeMap; + +import org.onap.aaf.misc.env.Env; +import org.onap.aaf.misc.env.TimeTaken; +import org.onap.aaf.misc.env.Trans; + +import com.datastax.driver.core.ResultSet; +import com.datastax.driver.core.Row; +import com.datastax.driver.core.Session; +import com.datastax.driver.core.SimpleStatement; +import com.datastax.driver.core.Statement; + +public class Perm implements Comparable { + public static final TreeMap> data = new TreeMap>(); + public static final TreeMap keys = new TreeMap(); + private static List deletePerms = new ArrayList(); + + public final String ns, type, instance, action,description; + private String fullType = null, fullPerm = null, encode = null; + public final Set roles; + + public String encode() { + if(encode == null) { + encode = ns + '|' + type + '|' + instance + '|' + action; + } + return encode; + } + + public String fullType() { + if(fullType==null) { + fullType = ns + '.' + type; + } + return fullType; + } + + public String fullPerm() { + if(fullPerm==null) { + fullPerm = ns + '.' + type + '|' + instance + '|' + action; + } + return fullPerm; + } + + public Perm(String ns, String type, String instance, String action, String description, Set roles) { + this.ns = ns; + this.type = type; + this.instance = instance; + this.action = action; + this.description = description; + // 2.0.11 +// this.full = encode();//ns+'.'+type+'|'+instance+'|'+action; + this.roles = roles; + } + + public static void load(Trans trans, Session session) { + load(trans, session, "select ns, type, instance, action, description, roles from authz.perm;"); + } + + public static void loadOneNS(Trans trans, Session session, String ns) { + load(trans, session, "select ns, type, instance, action, description, roles from authz.perm WHERE ns='" + ns + "';"); + + } + + private static void load(Trans trans, Session session, String query) { + // + trans.info().log( "query: " + query ); + TimeTaken tt = trans.start("Read Perms", Env.REMOTE); + ResultSet results; + try { + Statement stmt = new SimpleStatement( query ); + results = session.execute(stmt); + } finally { + tt.done(); + } + + try { + Iterator iter = results.iterator(); + Row row; + tt = trans.start("Load Perms", Env.SUB); + try { + while(iter.hasNext()) { + row = iter.next(); + Perm pk = new Perm(row.getString(0),row.getString(1),row.getString(2),row.getString(3), row.getString(4), row.getSet(5,String.class)); + keys.put(pk.encode(), pk); + data.put(pk,pk.roles); + } + } finally { + tt.done(); + } + } finally { + trans.info().log("Found",data.size(),"perms"); + } + } + + public static long count(Trans trans, Session session) { + String query = "select count(*) from authz.perm LIMIT 1000000;"; + trans.info().log( "query: " + query ); + TimeTaken tt = trans.start("Count Namespaces", Env.REMOTE); + ResultSet results; + try { + Statement stmt = new SimpleStatement(query).setReadTimeoutMillis(12000); + results = session.execute(stmt); + return results.one().getLong(0); + } finally { + tt.done(); + } + } + + public String toString() { + return encode(); + } + + /* (non-Javadoc) + * @see java.lang.Object#hashCode() + */ + @Override + public int hashCode() { + return encode().hashCode(); + } + + /* (non-Javadoc) + * @see java.lang.Object#equals(java.lang.Object) + */ + @Override + public boolean equals(Object obj) { + return encode().equals(obj); + } + + @Override + public int compareTo(Perm o) { + return encode().compareTo(o.encode()); + } + + public static void stageRemove(Perm p) { + deletePerms.add(p); + } + + public static void executeRemove() { + for(Perm p : deletePerms) { + keys.remove(p.encode); + data.remove(p); + } + deletePerms.clear(); + } + +} \ No newline at end of file diff --git a/auth/auth-batch/src/main/java/org/onap/aaf/auth/helpers/Role.java b/auth/auth-batch/src/main/java/org/onap/aaf/auth/helpers/Role.java new file mode 100644 index 00000000..f48544b1 --- /dev/null +++ b/auth/auth-batch/src/main/java/org/onap/aaf/auth/helpers/Role.java @@ -0,0 +1,175 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.helpers; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Set; +import java.util.TreeMap; + +import org.onap.aaf.misc.env.Env; +import org.onap.aaf.misc.env.TimeTaken; +import org.onap.aaf.misc.env.Trans; + +import com.datastax.driver.core.ResultSet; +import com.datastax.driver.core.Row; +import com.datastax.driver.core.Session; +import com.datastax.driver.core.SimpleStatement; +import com.datastax.driver.core.Statement; + +public class Role implements Comparable { + public static final TreeMap> data = new TreeMap>(); + public static final TreeMap keys = new TreeMap(); + public static final TreeMap byName = new TreeMap(); + private static List deleteRoles = new ArrayList(); + + public final String ns, name, description; + private String full, encode; + public final Set perms; + + public Role(String full) { + ns = name = description = ""; + this.full = full; + perms = new HashSet(); + } + + public Role(String ns, String name, String description,Set perms) { + this.ns = ns; + this.name = name; + this.description = description; + this.full = null; + this.encode = null; + this.perms = perms; + } + + public String encode() { + if(encode==null) { + encode = ns + '|' + name; + } + return encode; + } + + public String fullName() { + if(full==null) { + full = ns + '.' + name; + } + return full; + } + + public static void load(Trans trans, Session session ) { + load(trans,session,"select ns, name, description, perms from authz.role;"); + } + + public static void loadOneNS(Trans trans, Session session, String ns ) { + load(trans,session,"select ns, name, description, perms from authz.role WHERE ns='" + ns + "';"); + } + + private static void load(Trans trans, Session session, String query) { + trans.info().log( "query: " + query ); + TimeTaken tt = trans.start("Read Roles", Env.REMOTE); + + ResultSet results; + try { + Statement stmt = new SimpleStatement( query ); + results = session.execute(stmt); + } finally { + tt.done(); + } + + try { + Iterator iter = results.iterator(); + Row row; + tt = trans.start("Load Roles", Env.SUB); + try { + while(iter.hasNext()) { + row = iter.next(); + Role rk =new Role(row.getString(0),row.getString(1), row.getString(2),row.getSet(3,String.class)); + keys.put(rk.encode(), rk); + data.put(rk,rk.perms); + byName.put(rk.fullName(), rk); + } + } finally { + tt.done(); + } + } finally { + trans.info().log("Found",data.size(),"roles"); + } + } + + public static long count(Trans trans, Session session) { + String query = "select count(*) from authz.role LIMIT 1000000;"; + trans.info().log( "query: " + query ); + TimeTaken tt = trans.start("Count Namespaces", Env.REMOTE); + ResultSet results; + try { + Statement stmt = new SimpleStatement(query).setReadTimeoutMillis(12000); + results = session.execute(stmt); + return results.one().getLong(0); + } finally { + tt.done(); + } + } + + public String toString() { + return encode(); + } + + /* (non-Javadoc) + * @see java.lang.Object#hashCode() + */ + @Override + public int hashCode() { + return encode().hashCode(); + } + + /* (non-Javadoc) + * @see java.lang.Object#equals(java.lang.Object) + */ + @Override + public boolean equals(Object obj) { + return encode().equals(obj); + } + + @Override + public int compareTo(Role o) { + return encode().compareTo(o.encode()); + } + + public static String fullName(String role) { + return role.replace('|', '.'); + } + + public static void stageRemove(Role r) { + deleteRoles.add(r); + } + + public static void executeRemove() { + for(Role p : deleteRoles) { + keys.remove(p.encode); + data.remove(p); + } + deleteRoles.clear(); + } + +} \ No newline at end of file diff --git a/auth/auth-batch/src/main/java/org/onap/aaf/auth/helpers/UserRole.java b/auth/auth-batch/src/main/java/org/onap/aaf/auth/helpers/UserRole.java new file mode 100644 index 00000000..d990bb11 --- /dev/null +++ b/auth/auth-batch/src/main/java/org/onap/aaf/auth/helpers/UserRole.java @@ -0,0 +1,282 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.helpers; + +import java.io.PrintStream; +import java.util.ArrayList; +import java.util.Date; +import java.util.Iterator; +import java.util.List; +import java.util.TreeMap; + +import org.onap.aaf.auth.actions.URDelete; +import org.onap.aaf.auth.dao.cass.UserRoleDAO; +import org.onap.aaf.auth.dao.cass.UserRoleDAO.Data; +import org.onap.aaf.auth.env.AuthzTrans; +import org.onap.aaf.misc.env.Env; +import org.onap.aaf.misc.env.TimeTaken; +import org.onap.aaf.misc.env.Trans; +import org.onap.aaf.misc.env.util.Chrono; + +import com.datastax.driver.core.ResultSet; +import com.datastax.driver.core.Row; +import com.datastax.driver.core.Session; +import com.datastax.driver.core.SimpleStatement; +import com.datastax.driver.core.Statement; + +public class UserRole implements Cloneable, CacheChange.Data { + public static final List data = new ArrayList(); + public static final TreeMap> byUser = new TreeMap>(); + public static final TreeMap> byRole = new TreeMap>(); + private final static CacheChange cache = new CacheChange(); + private static PrintStream urDelete=System.out,urRecover=System.err; + private static int totalLoaded; + private static int deleted; + + private Data urdd; + + public UserRole(String user, String ns, String rname, Date expires) { + urdd = new UserRoleDAO.Data(); + urdd.user = user; + urdd.role = ns + '.' + rname; + urdd.ns = ns; + urdd.rname = rname; + urdd.expires = expires; + } + + public UserRole(String user, String role, String ns, String rname, Date expires) { + urdd = new UserRoleDAO.Data(); + urdd.user = user; + urdd.role = role; + urdd.ns = ns; + urdd.rname = rname; + urdd.expires = expires; + } + + public static void load(Trans trans, Session session, Creator creator ) { + load(trans,session,creator,null); + } + + public static void loadOneRole(Trans trans, Session session, Creator creator, String role) { + load(trans,session,creator,"role='" + role +"' ALLOW FILTERING;"); + } + + public static void loadOneUser(Trans trans, Session session, Creator creator, String user ) { + load(trans,session,creator,"role='"+ user +"';"); + } + + private static void load(Trans trans, Session session, Creator creator, String where) { + String query = creator.query(where); + trans.info().log( "query: " + query ); + TimeTaken tt = trans.start("Read UserRoles", Env.REMOTE); + + ResultSet results; + try { + Statement stmt = new SimpleStatement( query ); + results = session.execute(stmt); + } finally { + tt.done(); + } + try { + Iterator iter = results.iterator(); + Row row; + tt = trans.start("Load UserRole", Env.SUB); + try { + while(iter.hasNext()) { + ++totalLoaded; + row = iter.next(); + UserRole ur = creator.create(row); + data.add(ur); + + List lur = byUser.get(ur.urdd.user); + if(lur==null) { + lur = new ArrayList(); + byUser.put(ur.urdd.user, lur); + } + lur.add(ur); + + lur = byRole.get(ur.urdd.role); + if(lur==null) { + lur = new ArrayList(); + byRole.put(ur.urdd.role, lur); + } + lur.add(ur); + } + } finally { + tt.done(); + } + } finally { + trans.info().log("Loaded",totalLoaded,"UserRoles"); + } + } + + public int totalLoaded() { + return totalLoaded(); + } + + public int deleted() { + return deleted; + } + + @Override + public void expunge() { + data.remove(this); + + List lur = byUser.get(urdd.user); + if(lur!=null) { + lur.remove(this); + } + + lur = byRole.get(urdd.role); + if(lur!=null) { + lur.remove(this); + } + } + + public static void setDeleteStream(PrintStream ds) { + urDelete = ds; + } + + public static void setRecoverStream(PrintStream ds) { + urRecover = ds; + } + + public static long count(Trans trans, Session session) { + String query = "select count(*) from authz.user_role LIMIT 1000000;"; + trans.info().log( "query: " + query ); + TimeTaken tt = trans.start("Count Namespaces", Env.REMOTE); + ResultSet results; + try { + Statement stmt = new SimpleStatement(query).setReadTimeoutMillis(12000); + results = session.execute(stmt); + return results.one().getLong(0); + } finally { + tt.done(); + } + } + + + public static Creator v2_0_11 = new Creator() { + @Override + public UserRole create(Row row) { + return new UserRole(row.getString(0), row.getString(1), row.getString(2),row.getString(3),row.getTimestamp(4)); + } + + @Override + public String select() { + return "select user,role,ns,rname,expires from authz.user_role"; + } + }; + + public UserRoleDAO.Data urdd() { + return urdd; + } + + public String user() { + return urdd.user; + }; + + public String role() { + return urdd.role; + } + + public String ns() { + return urdd.ns; + } + + public String rname() { + return urdd.rname; + } + + public Date expires() { + return urdd.expires; + } + + public void expires(Date time) { + urdd.expires = time; + } + + + + public String toString() { + return "\"" + urdd.user + "\",\"" + urdd.role + "\",\"" + urdd.ns + "\",\"" + urdd.rname + "\",\""+ Chrono.dateOnlyStamp(urdd.expires); + } + + public static UserRole get(String u, String r) { + List lur = byUser.get(u); + if(lur!=null) { + for(UserRole ur : lur) { + if(ur.urdd.role.equals(r)) { + return ur; + } + } + } + return null; + } + + // CACHE Calling + private static final String logfmt = "%s UserRole - %s: %s-%s (%s, %s) expiring %s"; + private static final String replayfmt = "%s|%s|%s|%s|%s\n"; + private static final String deletefmt = "# %s\n"+replayfmt; + + // SAFETY - DO NOT DELETE USER ROLES DIRECTLY FROM BATCH FILES!!! + // We write to a file, and validate. If the size is iffy, we email Support + public void delayDelete(AuthzTrans trans, String text, boolean dryRun) { + String dt = Chrono.dateTime(urdd.expires); + if(dryRun) { + trans.info().printf(logfmt,text,"Would Delete",urdd.user,urdd.role,urdd.ns,urdd.rname,dt); + } else { + trans.info().printf(logfmt,text,"Staged Deletion",urdd.user,urdd.role,urdd.ns,urdd.rname,dt); + } + urDelete.printf(deletefmt,text,urdd.user,urdd.role,dt,urdd.ns,urdd.rname); + urRecover.printf(replayfmt,urdd.user,urdd.role,dt,urdd.ns,urdd.rname); + + cache.delayedDelete(this); + ++deleted; + } + + + /** + * Calls expunge() for all deleteCached entries + */ + public static void resetLocalData() { + cache.resetLocalData(); + } + + public static int sizeForDeletion() { + return cache.cacheSize(); + } + + public static boolean pendingDelete(UserRole ur) { + return cache.contains(ur); + } + + public static void actuateDeletionNow(AuthzTrans trans, URDelete directDel) { + for(UserRole ur : cache.getRemoved()) { + directDel.exec(trans, ur, "Actuating UserRole Deletion"); + } + cache.getRemoved().clear(); + cache.resetLocalData(); + } + + +} \ No newline at end of file diff --git a/auth/auth-batch/src/main/java/org/onap/aaf/auth/reports/ExpiringNext.java b/auth/auth-batch/src/main/java/org/onap/aaf/auth/reports/ExpiringNext.java new file mode 100644 index 00000000..2412f496 --- /dev/null +++ b/auth/auth-batch/src/main/java/org/onap/aaf/auth/reports/ExpiringNext.java @@ -0,0 +1,143 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.reports; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Date; +import java.util.GregorianCalendar; +import java.util.List; + +import org.onap.aaf.auth.Batch; +import org.onap.aaf.auth.dao.cass.CredDAO; +import org.onap.aaf.auth.env.AuthzTrans; +import org.onap.aaf.auth.helpers.Cred; +import org.onap.aaf.auth.helpers.UserRole; +import org.onap.aaf.auth.helpers.Cred.Instance; +import org.onap.aaf.auth.org.OrganizationException; +import org.onap.aaf.misc.env.APIException; +import org.onap.aaf.misc.env.Env; +import org.onap.aaf.misc.env.TimeTaken; +import org.onap.aaf.misc.env.util.Chrono; + +public class ExpiringNext extends Batch { + + public ExpiringNext(AuthzTrans trans) throws APIException, IOException, OrganizationException { + super(trans.env()); + trans.info().log("Starting Connection Process"); + + TimeTaken tt0 = trans.start("Cassandra Initialization", Env.SUB); + try { + TimeTaken tt = trans.start("Connect to Cluster", Env.REMOTE); + try { + session = cluster.connect(); + } finally { + tt.done(); + } + + UserRole.load(trans, session, UserRole.v2_0_11); + Cred.load(trans, session); + } finally { + tt0.done(); + } + } + + @Override + protected void run(AuthzTrans trans) { + GregorianCalendar gc = new GregorianCalendar(); + Date now = gc.getTime(); + gc.add(GregorianCalendar.WEEK_OF_MONTH, 2); + Date twoWeeks = gc.getTime(); + // Set time way off + gc.set(GregorianCalendar.YEAR, 3000); + Date earliestUR = gc.getTime(); + Date earliestCred = gc.getTime(); + // Run for Roles + List expiring = new ArrayList(); + + trans.info().log("Checking for Expired UserRoles"); + for(UserRole ur : UserRole.data) { + if(ur.expires().after(now)) { + if(ur.expires().before(twoWeeks)) { + expiring.add(Chrono.dateOnlyStamp(ur.expires()) + ":\t" + ur.user() + '\t' + ur.role()); + } + if(ur.expires().before(earliestUR)) { + earliestUR = ur.expires(); + } + } + } + + if(expiring.size()>0) { + Collections.sort(expiring,Collections.reverseOrder()); + for(String s : expiring) { + System.err.print('\t'); + System.err.println(s); + } + trans.info().printf("Earliest Expiring UR is %s\n\n", Chrono.dateOnlyStamp(earliestUR)); + } else { + trans.info().printf("No Expiring UserRoles within 2 weeks"); + } + + expiring.clear(); + + trans.info().log("Checking for Expired Credentials"); + for( Cred creds : Cred.data.values()) { + Instance lastInstance=null; + for(Instance inst : creds.instances) { + if(inst.type==CredDAO.BASIC_AUTH || inst.type==CredDAO.BASIC_AUTH_SHA256) { + if(lastInstance == null || inst.expires.after(lastInstance.expires)) { + lastInstance = inst; + } + } + } + if(lastInstance!=null) { + if(lastInstance.expires.after(now)) { + if(lastInstance.expires.before(twoWeeks)) { + expiring.add(Chrono.dateOnlyStamp(lastInstance.expires) + ": \t" + creds.id); + } + } + if(lastInstance.expires.before(earliestCred)) { + earliestCred = lastInstance.expires; + } + } + } + + if(expiring.size()>0) { + Collections.sort(expiring,Collections.reverseOrder()); + for(String s : expiring) { + System.err.print('\t'); + System.err.println(s); + } + trans.info().printf("Earliest Expiring Cred is %s\n\n", Chrono.dateOnlyStamp(earliestCred)); + } else { + trans.info().printf("No Expiring Creds within 2 weeks"); + } + + } + + @Override + protected void _close(AuthzTrans trans) { + session.close(); + } + +} diff --git a/auth/auth-batch/src/main/java/org/onap/aaf/auth/update/Expiring.java b/auth/auth-batch/src/main/java/org/onap/aaf/auth/update/Expiring.java new file mode 100644 index 00000000..d3b80d21 --- /dev/null +++ b/auth/auth-batch/src/main/java/org/onap/aaf/auth/update/Expiring.java @@ -0,0 +1,503 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.update; + +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.Date; +import java.util.GregorianCalendar; +import java.util.List; +import java.util.UUID; + +import org.onap.aaf.auth.Batch; +import org.onap.aaf.auth.BatchPrincipal; +import org.onap.aaf.auth.actions.Action; +import org.onap.aaf.auth.actions.ActionDAO; +import org.onap.aaf.auth.actions.CacheTouch; +import org.onap.aaf.auth.actions.CredDelete; +import org.onap.aaf.auth.actions.CredPrint; +import org.onap.aaf.auth.actions.Email; +import org.onap.aaf.auth.actions.Message; +import org.onap.aaf.auth.actions.URDelete; +import org.onap.aaf.auth.actions.URFutureApprove; +import org.onap.aaf.auth.actions.URFutureApproveExec; +import org.onap.aaf.auth.actions.URPrint; +import org.onap.aaf.auth.dao.cass.ApprovalDAO; +import org.onap.aaf.auth.dao.cass.CredDAO; +import org.onap.aaf.auth.dao.cass.FutureDAO; +import org.onap.aaf.auth.dao.hl.Function.FUTURE_OP; +import org.onap.aaf.auth.dao.hl.Function.OP_STATUS; +import org.onap.aaf.auth.env.AuthzTrans; +import org.onap.aaf.auth.helpers.Approval; +import org.onap.aaf.auth.helpers.Cred; +import org.onap.aaf.auth.helpers.Future; +import org.onap.aaf.auth.helpers.NS; +import org.onap.aaf.auth.helpers.Role; +import org.onap.aaf.auth.helpers.UserRole; +import org.onap.aaf.auth.helpers.Cred.Instance; +import org.onap.aaf.auth.layer.Result; +import org.onap.aaf.auth.org.OrganizationException; +import org.onap.aaf.auth.org.Organization.Identity; +import org.onap.aaf.misc.env.APIException; +import org.onap.aaf.misc.env.Env; +import org.onap.aaf.misc.env.TimeTaken; +import org.onap.aaf.misc.env.util.Chrono; + +public class Expiring extends Batch { + private CredPrint crPrint; + private URFutureApprove urFutureApprove; + private URFutureApproveExec urFutureApproveExec; + private CredDelete crDelete; + private URDelete urDelete; + private final CacheTouch cacheTouch; + private final AuthzTrans noAvg; + private final ApprovalDAO apprDAO; + private final FutureDAO futureDAO; + private final PrintStream urDeleteF,urRecoverF; + private final URPrint urPrint; + private Email email; + private File deletesFile; + + public Expiring(AuthzTrans trans) throws APIException, IOException, OrganizationException { + super(trans.env()); + trans.info().log("Starting Connection Process"); + + noAvg = env.newTransNoAvg(); + noAvg.setUser(new BatchPrincipal("batch:Expiring")); + + TimeTaken tt0 = trans.start("Cassandra Initialization", Env.SUB); + try { + crPrint = new CredPrint("Expired:"); + + TimeTaken tt = trans.start("Connect to Cluster with DAOs", Env.REMOTE); + try { + urFutureApprove = new URFutureApprove(trans, cluster,isDryRun()); + checkOrganizationAcccess(trans, urFutureApprove.question()); + urFutureApproveExec = new URFutureApproveExec(trans, urFutureApprove); + urPrint = new URPrint("User Roles:"); + crDelete = new CredDelete(trans, urFutureApprove); + urDelete = new URDelete(trans,urFutureApprove); + cacheTouch = new CacheTouch(trans, urFutureApprove); + + // Reusing... don't destroy + apprDAO = urFutureApprove.question().approvalDAO; + futureDAO = urFutureApprove.question().futureDAO; + + TimeTaken tt2 = trans.start("Connect to Cluster", Env.REMOTE); + try { + session = urFutureApprove.getSession(trans); + } finally { + tt2.done(); + } + } finally { + tt.done(); + } + + File data_dir = new File(env.getProperty("aaf_data_dir")); + if(!data_dir.exists() || !data_dir.canWrite() || !data_dir.canRead()) { + throw new IOException("Cannot read/write to Data Directory "+ data_dir.getCanonicalPath() + ": EXITING!!!"); + } + UserRole.setDeleteStream( + urDeleteF = new PrintStream(new FileOutputStream(deletesFile = new File(data_dir,"UserRoleDeletes.dat"),false))); + UserRole.setRecoverStream( + urRecoverF = new PrintStream(new FileOutputStream(new File(data_dir,"UserRoleRecover.dat"),false))); + UserRole.load(trans, session, UserRole.v2_0_11); + + Cred.load(trans, session); + NS.load(trans, session,NS.v2_0_11); + Future.load(trans,session,Future.withConstruct); + Approval.load(trans,session,Approval.v2_0_17); + Role.load(trans, session); + + email = new Email(); + email.subject("AAF Expiring Process Alert (ENV: %s)",batchEnv); + email.preamble("Expiring Process Alert for %s",batchEnv); + email.signature("Sincerely,\nAAF Expiring Batch Process\n"); + String address = env.getProperty("ALERT_TO_ADDRESS"); + if(address==null) { + throw new APIException("ALERT_TO_ADDRESS property is required"); + } + email.addTo(address); + + } catch (OrganizationException e) { + throw new APIException("Error getting valid Organization",e); + } finally { + tt0.done(); + } + } + + @Override + protected void run(AuthzTrans trans) { + // Setup Date boundaries + + final GregorianCalendar gc = new GregorianCalendar(); + final Date now = gc.getTime(); + + gc.add(GregorianCalendar.MONTH, 1); + Date future = gc.getTime(); +// Date earliest = null; + + // reset + gc.setTime(now); + gc.add(GregorianCalendar.DAY_OF_MONTH, -7); // save Expired Roles for 7 days. + Date tooLate = gc.getTime(); + + TimeTaken tt; + + // Clean out Approvals UserRoles are fixed up. + String memo; + for(List la : Approval.byUser.values()) { + for(Approval a : la ) { + memo = a.getMemo(); + if(memo!=null && (memo.contains("Re-Approval") || memo.contains("Re-Validate"))) { + String role = a.getRole(); + if(role!=null) { + UserRole ur = UserRole.get(a.getUser(), a.getRole()); + Future f=null; + if(ur!=null) { + if(ur.expires().after(future)) { // no need for Approval anymore + a.delayDelete(noAvg, apprDAO, dryRun, "User Role already Extended"); + UUID tkt = a.getTicket(); + if(tkt!=null) { + f = Future.data.get(tkt); + } + } + } else { + a.delayDelete(noAvg, apprDAO, dryRun, "User Role does not exist"); + f = Future.data.get(a.getTicket()); + } + if(f!=null) { + f.delayedDelete(noAvg, futureDAO, dryRun, "Approvals removed"); + } + } + } + } + } + try { + trans.info().log("### Removed",Future.sizeForDeletion(),"Future and",Approval.sizeForDeletion(),"Approvals"); + Future.resetLocalData(); + Approval.resetLocalData(); + } catch (Throwable t) { + t.printStackTrace(); + } + + // Run for Expired Futures + trans.info().log("Checking for Expired Approval/Futures"); + tt = trans.start("Delete old Futures", Env.REMOTE); + trans.info().log("### Running Future Execution on ",Future.data.size(), "Items"); + // Execute any Futures waiting + for(Future f : Future.data.values()) { + if(f.memo().contains("Re-Approval") || f.memo().contains("Re-Validate")) { + List la = Approval.byTicket.get(f.id()); + if(la!=null) { + Result ruf = urFutureApproveExec.exec(noAvg,la,f); + if(ruf.isOK()) { + switch(ruf.value) { + case P: + break; + case E: + case D: + case L: + f.delayedDelete(noAvg, futureDAO, dryRun,OP_STATUS.L.desc()); + Approval.delayDelete(noAvg, apprDAO, dryRun, la,OP_STATUS.L.desc()); + break; + } + } + } + } + } + try { + trans.info().log("### Removed",Future.sizeForDeletion(),"Future and",Approval.sizeForDeletion(),"Approvals"); + Future.resetLocalData(); + Approval.resetLocalData(); + } catch (Throwable t) { + t.printStackTrace(); + } + + + trans.info().log("### Remove Expired on ",Future.data.size(), "Items, or premature ones"); + // Remove Expired + String expiredBeforeNow = "Expired before " + tooLate; + String expiredAfterFuture = "Expired after " + future; + try { + for(Future f : Future.data.values()) { + if(f.expires().before(tooLate)) { + f.delayedDelete(noAvg,futureDAO,dryRun, expiredBeforeNow); + Approval.delayDelete(noAvg, apprDAO, dryRun, Approval.byTicket.get(f.id()), expiredBeforeNow); + } else if(f.expires().after(future)) { + f.delayedDelete(noAvg,futureDAO,dryRun, expiredAfterFuture); + Approval.delayDelete(noAvg,apprDAO,dryRun, Approval.byTicket.get(f.id()), expiredAfterFuture); + } + } + try { + trans.info().log("### Removed",Future.sizeForDeletion(),"Future and",Approval.sizeForDeletion(),"Approvals"); + Future.resetLocalData(); + Approval.resetLocalData(); + } catch (Throwable t) { + t.printStackTrace(); + } + } finally { + tt.done(); + } + + trans.info().log("### Checking Approvals valid (",Approval.byApprover.size(),"Items)"); + // Make sure users of Approvals are still valid + for(List lapp : Approval.byTicket.values()) { + for(Approval app : lapp) { + Future f; + if(app.getTicket()==null) { + f = null; + } else { + f = Future.data.get(app.getTicket()); + if(Future.pendingDelete(f)) { + f=null; + } + } + String msg; + if(f!=null && app.getRole()!=null && Role.byName.get(app.getRole())==null) { + f.delayedDelete(noAvg,futureDAO,dryRun,msg="Role '" + app.getRole() + "' no longer exists"); + Approval.delayDelete(noAvg,apprDAO,dryRun, Approval.byTicket.get(f.id()), msg); + continue; + } + + switch(app.getStatus()) { + case "pending": + if(f==null) { + app.delayDelete(noAvg,apprDAO, isDryRun(), "ticketDeleted"); + continue; + } + switch(app.getType()) { + case "owner": + boolean anOwner=false; + String approle = app.getRole(); + if(approle!=null) { + Role role = Role.byName.get(approle); + if(role==null) { + app.delayDelete(noAvg, apprDAO, dryRun, "Role No Longer Exists"); + continue; + } else { + // Make sure Owner Role exists + String owner = role.ns + ".owner"; + if(Role.byName.containsKey(owner)) { + List lur = UserRole.byRole.get(owner); + if(lur != null) { + for(UserRole ur : lur) { + if(ur.user().equals(app.getApprover())) { + anOwner = true; + break; + } + } + } + } + } + if(!anOwner) { + app.delayDelete(noAvg, apprDAO, dryRun, "No longer Owner"); + } + + } + break; + case "supervisor": + try { + Identity identity = org.getIdentity(noAvg, app.getUser()); + if(identity==null) { + if(f!=null) { + f.delayedDelete(noAvg,futureDAO,dryRun,msg = app.getUser() + " is no longer associated with " + org.getName()); + Approval.delayDelete(noAvg,apprDAO,dryRun, Approval.byTicket.get(f.id()), msg); + } + } else { + if(!app.getApprover().equals(identity.responsibleTo().fullID())) { + if(f!=null) { + f.delayedDelete(noAvg,futureDAO,dryRun,msg = app.getApprover() + " is no longer a Supervisor of " + app.getUser()); + Approval.delayDelete(noAvg,apprDAO,dryRun, Approval.byTicket.get(f.id()), msg); + } + } + } + } catch (OrganizationException e) { + e.printStackTrace(); + } + break; + } + break; + } + } + } + try { + trans.info().log("### Removed",Future.sizeForDeletion(),"Future and",Approval.sizeForDeletion(),"Approvals"); + Future.resetLocalData(); + Approval.resetLocalData(); + } catch (Throwable t) { + t.printStackTrace(); + } + + int count = 0, deleted=0, delayedURDeletes = 0; + + // Run for User Roles + trans.info().log("Checking for Expired User Roles"); + try { + for(UserRole ur : UserRole.data) { + if(org.getIdentity(noAvg, ur.user())==null) { // if not part of Organization; + if(isSpecial(ur.user())) { + trans.info().log(ur.user(),"is not part of organization, but may not be deleted"); + } else { + ur.delayDelete(noAvg, "Not Part of Organization", dryRun); + ++deleted; + ++delayedURDeletes; + } + } else { + if(NS.data.get(ur.ns())==null) { + ur.delayDelete(noAvg,"Namespace " + ur.ns() + " does not exist.",dryRun); + ++delayedURDeletes; + ++deleted; + } else if(!Role.byName.containsKey(ur.role())) { + ur.delayDelete(noAvg,"Role " + ur.role() + " does not exist.",dryRun); + ++deleted; + ++delayedURDeletes; + } else if(ur.expires().before(tooLate)) { + if("owner".equals(ur.rname())) { // don't delete Owners, even if Expired + urPrint.exec(noAvg,ur,"Owner Expired (but not deleted)"); + } else { + // In this case, when UR is expired, not dependent on other lookups, we delete straight out. + urDelete.exec(noAvg, ur,"Expired before " + tooLate); + ++deleted; + } + //trans.logAuditTrail(trans.info()); + } else if(ur.expires().before(future) && ur.expires().after(now)) { + ++count; + // Is there an Approval set already + boolean needNew = true; + if(ur.role()!=null && ur.user()!=null) { + List abm = Approval.byUser.get(ur.user()); + if(abm!=null) { + for(Approval a : abm) { + if(a.getOperation().equals(FUTURE_OP.A.name()) && ur.role().equals(a.getRole())) { + if(Future.data.get(a.getTicket())!=null) { + needNew = false; + break; + } + } + } + } + } + if(needNew) { + urFutureApprove.exec(noAvg, ur,""); + } + } + } + } + } catch (OrganizationException e) { + env.info().log(e,"Exiting ..."); + } finally { + env.info().log("Found",count,"user roles expiring before",future); + env.info().log("deleting",deleted,"user roles expiring before",tooLate); + } + + // Actualize UR Deletes, or send Email + if(UserRole.sizeForDeletion()>0) { + count+=UserRole.sizeForDeletion(); + double onePercent = 0.01; + if(((double)UserRole.sizeForDeletion())/UserRole.data.size() > onePercent) { + Message msg = new Message(); + try { + msg.line("Found %d of %d UserRoles marked for Deletion in file %s", + delayedURDeletes,UserRole.data.size(),deletesFile.getCanonicalPath()); + } catch (IOException e) { + msg.line("Found %d of %d UserRoles marked for Deletion.\n", + delayedURDeletes); + } + msg.line("Review the File. If data is ok, Use ExpiringP2 BatchProcess to complete the deletions"); + + email.msg(msg); + email.exec(trans, org, "Email Support"); + } else { + urDeleteF.flush(); + try { + BufferedReader br = new BufferedReader(new FileReader(deletesFile)); + try { + ExpiringP2.deleteURs(noAvg, br, urDelete, null /* don't touch Cache here*/); + } finally { + br.close(); + } + } catch (IOException io) { + noAvg.error().log(io); + } + } + } + if(count>0) { + String str = String.format("%d UserRoles modified or deleted", count); + cacheTouch.exec(trans, "user_role", str); + } + + // Run for Creds + trans.info().log("Checking for Expired Credentials"); + System.out.flush(); + count = 0; + try { + CredDAO.Data crd = new CredDAO.Data(); + Date last = null; + for( Cred creds : Cred.data.values()) { + crd.id = creds.id; + for(int type : creds.types()) { + crd.type = type; + for( Instance inst : creds.instances) { + if(inst.expires.before(tooLate)) { + crd.expires = inst.expires; + crDelete.exec(noAvg, crd,"Expired before " + tooLate); + } else if(last==null || inst.expires.after(last)) { + last = inst.expires; + } + } + if(last!=null) { + if(last.before(future)) { + crd.expires = last; + crPrint.exec(noAvg, crd,""); + ++count; + } + } + } + } + } finally { + String str = String.format("Found %d current creds expiring before %s", count, Chrono.dateOnlyStamp(future)); + if(count>0) { + cacheTouch.exec(trans, "cred", str); + } + } + + } + + @Override + protected void _close(AuthzTrans trans) { + aspr.info("End " + this.getClass().getSimpleName() + " processing" ); + for(Action action : new Action[] {crDelete}) { + if(action instanceof ActionDAO) { + ((ActionDAO)action).close(trans); + } + } + session.close(); + urDeleteF.close(); + urRecoverF.close(); + } + +} diff --git a/auth/auth-batch/src/main/java/org/onap/aaf/auth/update/ExpiringP2.java b/auth/auth-batch/src/main/java/org/onap/aaf/auth/update/ExpiringP2.java new file mode 100644 index 00000000..f568b330 --- /dev/null +++ b/auth/auth-batch/src/main/java/org/onap/aaf/auth/update/ExpiringP2.java @@ -0,0 +1,158 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.update; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileReader; +import java.io.IOException; +import java.text.ParseException; +import java.util.HashMap; +import java.util.Map; +import java.util.Map.Entry; + +import org.onap.aaf.auth.Batch; +import org.onap.aaf.auth.BatchPrincipal; +import org.onap.aaf.auth.actions.Action; +import org.onap.aaf.auth.actions.ActionDAO; +import org.onap.aaf.auth.actions.CacheTouch; +import org.onap.aaf.auth.actions.URDelete; +import org.onap.aaf.auth.env.AuthzTrans; +import org.onap.aaf.auth.helpers.UserRole; +import org.onap.aaf.auth.org.OrganizationException; +import org.onap.aaf.cadi.util.Split; +import org.onap.aaf.misc.env.APIException; +import org.onap.aaf.misc.env.Env; +import org.onap.aaf.misc.env.TimeTaken; +import org.onap.aaf.misc.env.util.Chrono; + +public class ExpiringP2 extends Batch { + private final URDelete urDelete; + private final CacheTouch cacheTouch; + private final AuthzTrans noAvg; + private final BufferedReader urDeleteF; + + public ExpiringP2(AuthzTrans trans) throws APIException, IOException, OrganizationException { + super(trans.env()); + trans.info().log("Starting Connection Process"); + + noAvg = env.newTransNoAvg(); + noAvg.setUser(new BatchPrincipal("batch:ExpiringP2")); + + TimeTaken tt0 = trans.start("Cassandra Initialization", Env.SUB); + try { + urDelete = new URDelete(trans, cluster,isDryRun()); + TimeTaken tt2 = trans.start("Connect to Cluster", Env.REMOTE); + try { + session = urDelete.getSession(trans); + } finally { + tt2.done(); + } + cacheTouch = new CacheTouch(trans,urDelete); + + File data_dir = new File(env.getProperty("aaf_data_dir")); + if(!data_dir.exists() || !data_dir.canWrite() || !data_dir.canRead()) { + throw new IOException("Cannot read/write to Data Directory "+ data_dir.getCanonicalPath() + ": EXITING!!!"); + } + urDeleteF = new BufferedReader(new FileReader(new File(data_dir,"UserRoleDeletes.dat"))); + + } finally { + tt0.done(); + } + } + + @Override + protected void run(AuthzTrans trans) { + deleteURs(noAvg, urDeleteF, urDelete, cacheTouch); + } + + public static void deleteURs(AuthzTrans trans, BufferedReader urDeleteF, URDelete urDelete, CacheTouch cacheTouch) { + String line,prev=""; + try { + UserRole ur; + Map tally = new HashMap(); + int count=0; + try { + while((line=urDeleteF.readLine())!=null) { + if(line.startsWith("#")) { + Count cnt = tally.get(line); + if(cnt==null) { + tally.put(line, cnt=new Count()); + } + cnt.inc(); + prev = line; + } else { + String[] l = Split.splitTrim('|', line); + try { + // Note: following default order from "COPY TO" + ur = new UserRole(l[0],l[1],l[3],l[4],Chrono.iso8601Fmt.parse(l[2])); + urDelete.exec(trans, ur, prev); + ++count; + } catch (ParseException e) { + trans.error().log(e); + } + } + } + + System.out.println("Tallies of UserRole Deletions"); + for(Entry es : tally.entrySet()) { + System.out.printf(" %6d\t%20s\n", es.getValue().cnt,es.getKey()); + } + } finally { + if(cacheTouch!=null && count>0) { + cacheTouch.exec(trans, "user_roles", "Removing UserRoles"); + } + } + } catch (IOException e) { + trans.error().log(e); + } + + } + private static class Count { + private int cnt=0; + + public /*synchonized*/ void inc() { + ++cnt; + } + + public String toString() { + return Integer.toString(cnt); + } + } + + @Override + protected void _close(AuthzTrans trans) { + aspr.info("End " + this.getClass().getSimpleName() + " processing" ); + for(Action action : new Action[] {urDelete,cacheTouch}) { + if(action instanceof ActionDAO) { + ((ActionDAO)action).close(trans); + } + } + session.close(); + try { + urDeleteF.close(); + } catch (IOException e) { + trans.error().log(e); + } + } + +} diff --git a/auth/auth-batch/src/main/java/org/onap/aaf/auth/update/NotifyApprovals.java b/auth/auth-batch/src/main/java/org/onap/aaf/auth/update/NotifyApprovals.java new file mode 100644 index 00000000..3314694e --- /dev/null +++ b/auth/auth-batch/src/main/java/org/onap/aaf/auth/update/NotifyApprovals.java @@ -0,0 +1,236 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.update; + +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.PrintStream; +import java.util.ArrayList; +import java.util.Date; +import java.util.GregorianCalendar; +import java.util.List; +import java.util.Map.Entry; + +import org.onap.aaf.auth.Batch; +import org.onap.aaf.auth.BatchPrincipal; +import org.onap.aaf.auth.actions.Email; +import org.onap.aaf.auth.actions.EmailPrint; +import org.onap.aaf.auth.actions.Message; +import org.onap.aaf.auth.dao.CassAccess; +import org.onap.aaf.auth.dao.cass.ApprovalDAO; +import org.onap.aaf.auth.dao.cass.FutureDAO; +import org.onap.aaf.auth.dao.cass.HistoryDAO; +import org.onap.aaf.auth.env.AuthzTrans; +import org.onap.aaf.auth.helpers.Approval; +import org.onap.aaf.auth.helpers.Future; +import org.onap.aaf.auth.org.Organization; +import org.onap.aaf.auth.org.OrganizationException; +import org.onap.aaf.auth.org.OrganizationFactory; +import org.onap.aaf.auth.org.Organization.Identity; +import org.onap.aaf.misc.env.APIException; +import org.onap.aaf.misc.env.util.Chrono; + +public class NotifyApprovals extends Batch { + private static final String LINE = "----------------------------------------------------------------"; + private final HistoryDAO historyDAO; + private final ApprovalDAO apprDAO; + private final FutureDAO futureDAO; + private Email email; + private int maxEmails; + private final PrintStream ps; + private final AuthzTrans noAvg; + + public NotifyApprovals(AuthzTrans trans) throws APIException, IOException, OrganizationException { + super(trans.env()); + + noAvg = env.newTransNoAvg(); + noAvg.setUser(new BatchPrincipal("batch:NotifyApprovals")); + + historyDAO = new HistoryDAO(trans, cluster, CassAccess.KEYSPACE); + session = historyDAO.getSession(trans); + apprDAO = new ApprovalDAO(trans, historyDAO); + futureDAO = new FutureDAO(trans, historyDAO); + if(isDryRun()) { + email = new EmailPrint(); + maxEmails=3; + } else { + email = new Email(); + maxEmails = Integer.parseInt(trans.getProperty("MAX_EMAILS","3")); + } + email.subject("AAF Approval Notification (ENV: %s)",batchEnv); + email.preamble("AAF (MOTS 22830) is the AT&T Authorization System used by many AT&T Tools and Applications." + + "\n Your approval is required, which you may enter on the following page:" + + "\n\n\t%s/approve\n\n" + ,env.getProperty(GUI_URL)); + email.signature("Sincerely,\nAAF Team (Our MOTS# 22830)\n" + + "https://wiki.web.att.com/display/aaf/Contact+Us\n" + + "(Use 'Other Misc Requests (TOPS)')"); + + Approval.load(trans, session, Approval.v2_0_17); + Future.load(trans, session, Future.v2_0_17); // Skip the Construct Data + + ps = new PrintStream(new FileOutputStream(logDir() + "/email"+Chrono.dateOnlyStamp()+".log",true)); + ps.printf("### Approval Notify %s for %s%s\n",Chrono.dateTime(),batchEnv,dryRun?", DryRun":""); + } + + @Override + protected void run(AuthzTrans trans) { + GregorianCalendar gc = new GregorianCalendar(); + Date now = gc.getTime(); + String today = Chrono.dateOnlyStamp(now); + gc.add(GregorianCalendar.MONTH, -1); + gc=null; + + + Message msg = new Message(); + int emailCount = 0; + List pending = new ArrayList(); + boolean isOwner,isSupervisor; + for(Entry> es : Approval.byApprover.entrySet()) { + isOwner = isSupervisor = false; + String approver = es.getKey(); + if(approver.indexOf('@')<0) { + approver += org.getRealm(); + } + Date latestNotify=null, soonestExpire=null; + GregorianCalendar latest=new GregorianCalendar(); + GregorianCalendar soonest=new GregorianCalendar(); + pending.clear(); + + for(Approval app : es.getValue()) { + Future f = app.getTicket()==null?null:Future.data.get(app.getTicket()); + if(f==null) { // only Ticketed Approvals are valid.. the others are records. + // Approvals without Tickets are no longer valid. + if("pending".equals(app.getStatus())) { + app.setStatus("lapsed"); + app.update(noAvg,apprDAO,dryRun); // obeys dryRun + } + } else { + if((soonestExpire==null && f.expires()!=null) || (soonestExpire!=null && f.expires()!=null && soonestExpire.before(f.expires()))) { + soonestExpire=f.expires(); + } + + if("pending".equals(app.getStatus())) { + if(!isOwner) { + isOwner = "owner".equals(app.getType()); + } + if(!isSupervisor) { + isSupervisor = "supervisor".equals(app.getType()); + } + + if((latestNotify==null && app.getLast_notified()!=null) ||(latestNotify!=null && app.getLast_notified()!=null && latestNotify.before(app.getLast_notified()))) { + latestNotify=app.getLast_notified(); + } + pending.add(app); + } + } + } + + if(!pending.isEmpty()) { + boolean go = false; + if(latestNotify==null) { // never notified... make it so + go=true; + } else { + if(!today.equals(Chrono.dateOnlyStamp(latest))) { // already notified today + latest.setTime(latestNotify); + soonest.setTime(soonestExpire); + int year; + int days = soonest.get(GregorianCalendar.DAY_OF_YEAR)-latest.get(GregorianCalendar.DAY_OF_YEAR); + days+=((year=soonest.get(GregorianCalendar.YEAR))-latest.get(GregorianCalendar.YEAR))*365 + + (soonest.isLeapYear(year)?1:0); + if(days<7) { // If Expirations get within a Week (or expired), notify everytime. + go = true; + } + } + } + if(go) { + if(maxEmails>emailCount++) { + try { + Organization org = OrganizationFactory.obtain(env, approver); + Identity user = org.getIdentity(noAvg, approver); + if(user==null) { + ps.printf("Invalid Identity: %s\n", approver); + } else { + email.clear(); + msg.clear(); + email.addTo(user.email()); + msg.line(LINE); + msg.line("Why are you receiving this Notification?\n"); + if(isSupervisor) { + msg.line("%sYou are the supervisor of one or more employees who need access to tools which are protected by AAF. " + + "Your employees may ask for access to various tools and applications to do their jobs. ASPR requires " + + "that you are notified and approve their requests. The details of each need is provided when you click " + + "on webpage above.\n",isOwner?"1) ":""); + msg.line("Your participation in this process fulfills the ASPR requirement to re-authorize users in roles on a regular basis.\n\n"); + } + + if(isOwner) { + msg.line("%sYou are the listed owner of one or more AAF Namespaces. ASPR requires that those responsible for " + + "applications and their access review them regularly for accuracy. The AAF WIKI page for AT&T is https://wiki.web.att.com/display/aaf. " + + "More info regarding questions of being a Namespace Owner is available at https://wiki.web.att.com/pages/viewpage.action?pageId=594741363\n",isSupervisor?"2) ":""); + msg.line("Additionally, Credentials attached to the Namespace must be renewed regularly. While you may delegate certain functions to " + + "Administrators within your Namespace, you are ultimately responsible to make sure credentials do not expire.\n"); + msg.line("You may view the Namespaces you listed as Owner for in this AAF Env by viewing the following webpage:\n"); + msg.line(" %s/ns\n\n",env.getProperty(GUI_URL)); + + } + msg.line(" If you are unfamiliar with AAF, you might like to peruse the following links:" + + "\n\thttps://wiki.web.att.com/display/aaf/AAF+in+a+Nutshell" + + "\n\thttps://wiki.web.att.com/display/aaf/The+New+Person%%27s+Guide+to+AAF"); + msg.line("\n SPECIAL NOTE about SWM Management Groups: Understand that SWM management Groups correlate one-to-one to AAF Namespaces. " + + "(SWM uses AAF for the Authorization piece of Management Groups). You may be assigned the SWM Management Group by asking " + + "directly, or through any of the above stated automated processes. Auto-generated Namespaces typically look like 'com.att.44444.PROD' " + + "where '44444' is a MOTS ID, and 'PROD' is PROD|DEV|TEST, etc. For your convenience, the MOTS link is http://ebiz.sbc.com/mots.\n"); + msg.line(" Finally, realize that there are automated processes which create Machines and Resources via SWM, Kubernetes or other " + + "such tooling. If you or your predecessor requested them, you were set as the owner of the AAF Namespace created during " + + "that process.\n"); + msg.line(" For ALL QUESTIONS of why and how of SWM, and whether you or your reports can be removed, please contact SWM at " + + "https://wiki.web.att.com/display/swm/Support\n"); + + email.msg(msg); + email.exec(noAvg, org,""); + if(!isDryRun()) { + email.log(ps,"NotifyApprovals"); + for(Approval app : pending) { + app.setLastNotified(now); + app.update(noAvg, apprDAO, dryRun); + } + } + } + } catch (OrganizationException e) { + trans.info().log(e); + } + } + } + } + } + trans.info().printf("%d emails sent for %s", emailCount,batchEnv); + } + + @Override + protected void _close(AuthzTrans trans) { + futureDAO.close(trans); + apprDAO.close(trans); + historyDAO.close(trans); + ps.close(); + } +} diff --git a/auth/auth-batch/src/main/java/org/onap/aaf/auth/update/NotifyCredExpiring.java b/auth/auth-batch/src/main/java/org/onap/aaf/auth/update/NotifyCredExpiring.java new file mode 100644 index 00000000..bdf8347c --- /dev/null +++ b/auth/auth-batch/src/main/java/org/onap/aaf/auth/update/NotifyCredExpiring.java @@ -0,0 +1,321 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.update; + +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.PrintStream; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; + +import org.onap.aaf.auth.Batch; +import org.onap.aaf.auth.BatchPrincipal; +import org.onap.aaf.auth.actions.Email; +import org.onap.aaf.auth.actions.EmailPrint; +import org.onap.aaf.auth.actions.Message; +import org.onap.aaf.auth.dao.cass.CredDAO; +import org.onap.aaf.auth.dao.hl.Question; +import org.onap.aaf.auth.env.AuthzTrans; +import org.onap.aaf.auth.helpers.Cred; +import org.onap.aaf.auth.helpers.Notification; +import org.onap.aaf.auth.helpers.UserRole; +import org.onap.aaf.auth.helpers.Notification.TYPE; +import org.onap.aaf.auth.layer.Result; +import org.onap.aaf.auth.org.EmailWarnings; +import org.onap.aaf.auth.org.Organization; +import org.onap.aaf.auth.org.OrganizationException; +import org.onap.aaf.auth.org.OrganizationFactory; +import org.onap.aaf.auth.org.Organization.Identity; +import org.onap.aaf.misc.env.APIException; +import org.onap.aaf.misc.env.Env; +import org.onap.aaf.misc.env.TimeTaken; +import org.onap.aaf.misc.env.util.Chrono; + +import java.util.TreeMap; + + +public class NotifyCredExpiring extends Batch { + + private static final String UNKNOWN_ID = "unknown@deprecated.id"; + private static final String AAF_INSTANTIATED_MECHID = "AAF INSTANTIATED MECHID"; + private static final String EXPIRATION_DATE = "EXPIRATION DATE"; + private static final String QUICK_LINK = "QUICK LINK TO UPDATE PAGE"; + private static final String DASH_1 = "-----------------------"; + private static final String DASH_2 = "---------------"; + private static final String DASH_3 = "----------------------------------------------------"; + private static final String LINE = "\n----------------------------------------------------------------"; + private Email email; + private int maxEmails; + private final PrintStream ps; + private final AuthzTrans noAvg; + private String supportEmailAddr; + + public NotifyCredExpiring(AuthzTrans trans) throws APIException, IOException, OrganizationException { + super(trans.env()); + TimeTaken tt = trans.start("Connect to Cluster", Env.REMOTE); + try { + session = cluster.connect(); + } finally { + tt.done(); + } + + noAvg = env.newTransNoAvg(); + noAvg.setUser(new BatchPrincipal("batch:NotifyCredExpiring")); + + if((supportEmailAddr = env.getProperty("mailFromUserId"))==null) { + throw new APIException("mailFromUserId property must be set"); + } + if(isDryRun()) { + email = new EmailPrint(); + maxEmails=3; + maxEmails = Integer.parseInt(trans.getProperty("MAX_EMAILS","3")); + } else { + email = new Email(); + maxEmails = Integer.parseInt(trans.getProperty("MAX_EMAILS","3")); + } + + email.subject("AAF Password Expiration Notification (ENV: %s)",batchEnv); + email.preamble("AAF (MOTS 22830) is the AT&T Authorization System used by many AT&T Tools and Applications.\n\n" + + " The following Credentials are expiring on the dates shown. Failure to act before the expiration date " + + "will cause your App's Authentications to fail.\n"); + email.signature("Sincerely,\nAAF Team (Our MOTS# 22830)\n" + + "https://wiki.web.att.com/display/aaf/Contact+Us\n" + + "(Use 'Other Misc Requests (TOPS)')"); + + Cred.load(trans, session,CredDAO.BASIC_AUTH, CredDAO.BASIC_AUTH_SHA256); + Notification.load(trans, session, Notification.v2_0_18); + UserRole.load(trans, session, UserRole.v2_0_11); + + ps = new PrintStream(new FileOutputStream(logDir() + "/email"+Chrono.dateOnlyStamp()+".log",true)); + ps.printf("### Approval Notify %s for %s%s\n",Chrono.dateTime(),batchEnv,dryRun?", DryRun":""); + } + + @Override + protected void run(AuthzTrans trans) { + + EmailWarnings ewp = org.emailWarningPolicy(); + long now = System.currentTimeMillis(); + Date early = new Date(now+(ewp.credExpirationWarning()*2)); // 2 months back + Date must = new Date(now+ewp.credExpirationWarning()); // 1 months back + Date critical = new Date(now+ewp.emailUrgentWarning()); // 1 week + Date within2Weeks = new Date(now+604800000 * 2); + Date withinLastWeek = new Date(now-604800000); + Date tooLate = new Date(now); + + // Temp structures + Map lastCred = new HashMap(); + Map> ownerCreds = new TreeMap>(); + Date last; + + + List noOwner = new ArrayList(); + ownerCreds.put(UNKNOWN_ID,noOwner); + + // Get a list of ONLY the ones needing email by Owner + for(Entry> es : Cred.byNS.entrySet()) { + lastCred.clear(); + for(Cred c : es.getValue()) { + last = c.last(CredDAO.BASIC_AUTH,CredDAO.BASIC_AUTH_SHA256); + if(last!=null && last.after(tooLate) && last.before(early)) { + List ownerURList = UserRole.byRole.get(es.getKey()+".owner"); + if(ownerURList!=null) { + for(UserRole ur:ownerURList) { + String owner = ur.user(); + List llc = ownerCreds.get(owner); + if(llc==null) { + ownerCreds.put(owner, (llc=new ArrayList())); + } + llc.add(new LastCred(c,last)); + } + } else { + noOwner.add(new LastCred(c,last)); + } + } + } + } + + boolean bCritical,bNormal,bEarly; + int emailCount=0; + Message msg = new Message(); + Notification ownNotf; + StringBuilder logMessage = new StringBuilder(); + for(Entry> es : ownerCreds.entrySet()) { + String owner = es.getKey(); + boolean header = true; + try { + Organization org = OrganizationFactory.obtain(env, owner); + Identity user = org.getIdentity(noAvg, owner); + if(!UNKNOWN_ID.equals(owner) && user==null) { + ps.printf("Invalid Identity: %s\n", owner); + } else { + logMessage.setLength(0); + if(maxEmails>emailCount) { + bCritical=bNormal=bEarly = false; + email.clear(); + msg.clear(); + email.addTo(user==null?supportEmailAddr:user.email()); + + ownNotf = Notification.get(es.getKey(),TYPE.CN); + if(ownNotf==null) { + ownNotf = Notification.create(user==null?UNKNOWN_ID:user.fullID(), TYPE.CN); + } + last = ownNotf.last; + // Get Max ID size for formatting purposes + int length = AAF_INSTANTIATED_MECHID.length(); + for(LastCred lc : es.getValue()) { + length = Math.max(length, lc.cred.id.length()); + } + String id_exp_fmt = "\t%-"+length+"s %15s %s"; + + Collections.sort(es.getValue(),LastCred.COMPARE); + for(LastCred lc : es.getValue()) { + if(lc.last.after(must) && lc.last.before(early) && + (ownNotf.last==null || ownNotf.last.before(withinLastWeek))) { + if(!bEarly && header) { + msg.line("\tThe following are friendly 2 month reminders, just in case you need to schedule your updates early. " + + "You will be reminded next month\n"); + msg.line(id_exp_fmt, AAF_INSTANTIATED_MECHID,EXPIRATION_DATE, QUICK_LINK); + msg.line(id_exp_fmt, DASH_1, DASH_2, DASH_3); + header = false; + } + bEarly = true; + } else if(lc.last.after(critical) && lc.last.before(must) && + (ownNotf.last==null || ownNotf.last.before(withinLastWeek))) { + if(!bNormal) { + boolean last2wks = lc.last.before(within2Weeks); + if(last2wks) { + try { + Identity supvsr = user.responsibleTo(); + email.addCC(supvsr.email()); + } catch(OrganizationException e) { + trans.error().log(e, "Supervisor cannot be looked up"); + } + } + if(header) { + msg.line("\tIt is now important for you to update Passwords all all configurations using them for the following.\n" + + (last2wks?"\tNote: Your Supervisor is CCd\n":"\tNote: Your Supervisor will be notified if this is not being done before the last 2 weeks\n")); + msg.line(id_exp_fmt, AAF_INSTANTIATED_MECHID,EXPIRATION_DATE, QUICK_LINK); + msg.line(id_exp_fmt, DASH_1, DASH_2, DASH_3); + } + header = false; + } + bNormal=true; + } else if(lc.last.after(tooLate) && lc.last.before(critical)) { // Email Every Day, with Supervisor + if(!bCritical && header) { + msg.line("\t!!! WARNING: These Credentials will expire in LESS THAN ONE WEEK !!!!\n" + + "\tYour supervisor is added to this Email\n"); + msg.line(id_exp_fmt, AAF_INSTANTIATED_MECHID,EXPIRATION_DATE, QUICK_LINK); + msg.line(id_exp_fmt, DASH_1, DASH_2, DASH_3); + header = false; + } + bCritical = true; + try { + if(user!=null) { + Identity supvsr = user.responsibleTo(); + if(supvsr!=null) { + email.addCC(supvsr.email()); + supvsr = supvsr.responsibleTo(); + if(supvsr!=null) { + email.addCC(supvsr.email()); + } + } + } + } catch(OrganizationException e) { + trans.error().log(e, "Supervisor cannot be looked up"); + } + } + if(bEarly || bNormal || bCritical) { + if(logMessage.length()==0) { + logMessage.append("NotifyCredExpiring"); + } + logMessage.append("\n\t"); + logMessage.append(lc.cred.id); + logMessage.append('\t'); + logMessage.append(Chrono.dateOnlyStamp(lc.last)); + msg.line(id_exp_fmt, lc.cred.id, Chrono.dateOnlyStamp(lc.last)+" ",env.getProperty(GUI_URL)+"/creddetail?ns="+Question.domain2ns(lc.cred.id)); + } + } + + if(bEarly || bNormal || bCritical) { + msg.line(LINE); + msg.line("Why are you receiving this Notification?\n"); + msg.line("You are the listed owner of one or more AAF Namespaces. ASPR requires that those responsible for " + + "applications and their access review them regularly for accuracy. The AAF WIKI page for AT&T is https://wiki.web.att.com/display/aaf. " + + "You might like https://wiki.web.att.com/display/aaf/AAF+in+a+Nutshell. More detailed info regarding questions of being a Namespace Owner is available at https://wiki.web.att.com/pages/viewpage.action?pageId=594741363\n"); + msg.line("You may view the Namespaces you listed as Owner for in this AAF Env by viewing the following webpage:\n"); + msg.line(" %s/ns\n\n",env.getProperty(GUI_URL)); + email.msg(msg); + Result rv = email.exec(trans, org,""); + if(rv.isOK()) { + ++emailCount; + if(!isDryRun()) { + ownNotf.update(noAvg, session, false); + // SET LastNotification + } + email.log(ps,logMessage.toString()); + } else { + trans.error().log(rv.errorString()); + } + } + } + } + } catch (OrganizationException e) { + trans.info().log(e); + } + } + trans.info().printf("%d emails sent for %s", emailCount,batchEnv); + } + + private static class LastCred { + public Cred cred; + public Date last; + + public LastCred(Cred cred, Date last) { + this.cred = cred; + this.last = last; + } + + // Reverse Sort (Oldest on top) + public static Comparator COMPARE = new Comparator() { + @Override + public int compare(LastCred o1, LastCred o2) { + return o2.last.compareTo(o1.last); + } + }; + + public String toString() { + return Chrono.dateTime(last) + cred.toString(); + } + } + + @Override + protected void _close(AuthzTrans trans) { + session.close(); + ps.close(); + } +} diff --git a/auth/auth-cass/.gitignore b/auth/auth-cass/.gitignore new file mode 100644 index 00000000..d7c9d7e7 --- /dev/null +++ b/auth/auth-cass/.gitignore @@ -0,0 +1,9 @@ +/.settings +/bin +/Old +/target +/.classpath +/.project +/AAF_2.0.8_alter.zip +/logs/ +/target/ diff --git a/auth/auth-cass/docker/dinstall b/auth/auth-cass/docker/dinstall new file mode 100644 index 00000000..17d3e07d --- /dev/null +++ b/auth/auth-cass/docker/dinstall @@ -0,0 +1,29 @@ + +if [ "`docker ps -a | grep aaf_cass`" == "" ]; then + docker run --name aaf_cass -d cassandra:3.11 +else + docker exec aaf_cass mkdir -p /opt/app/cass_init + docker cp "../src/main/cql/." aaf_cass:/opt/app/cass_init +fi + +echo "Docker Installed Basic Cassandra on aaf_cass. Executing the following " +echo "NOTE: This creator provided is only a Single Instance. For more complex Cassandra, create independently" +echo "" +echo " cd /opt/app/cass_init" +echo " cqlsh -u root -p root -f keyspace.cql" +echo " cqlsh -u root -p root -f init.cql" +echo " cqlsh -u root -p root -f osaaf.cql" +echo "" +echo "The following will give you a temporary identity with which to start working, or emergency" +echo " cqlsh -u root -p root -f temp_identity.cql" +echo "Sleeping 10 seconds to allow Cassandra to start" +sleep 10 +docker exec -it aaf_cass bash -c '\ +cd /opt/app/cass_init; \ +echo "Creating Keyspace";cqlsh -u root -p root -f keyspace.cql;\ +echo "Creating init";cqlsh -u root -p root -f init.cql;\ +echo "Creating osaaf";cqlsh -u root -p root -f osaaf.cql;\ +echo "Creating temp Identity";cqlsh -u root -p root -f temp_identity.cql' + +echo "Inspecting aafcassadra. Use to get the IP address to update org.osaaf.cassandra.props" +docker inspect aaf_cass | grep '"IPAddress' | head -1 diff --git a/auth/auth-cass/pom.xml b/auth/auth-cass/pom.xml new file mode 100644 index 00000000..56f367d6 --- /dev/null +++ b/auth/auth-cass/pom.xml @@ -0,0 +1,110 @@ + + + + 4.0.0 + + org.onap.aaf.auth + parent + 2.1.0-SNAPSHOT + ../pom.xml + + + aaf-auth-cass + AAF Auth Cass + Cassandra Data Libraries for AAF Auth + jar + + + + Jonathan Gathman + jonathan.gathman@att.com + ATT + + Architect + Lead Developer + + + + Gabe Maurer + gabe.maurer@att.com + ATT + + Developer + + + + Ian Howell + ian.howell@att.com + ATT + + Developer + + + + + + + + org.onap.aaf.auth + aaf-auth-core + + + + org.onap.aaf.cadi + aaf-cadi-aaf + + + + com.datastax.cassandra + cassandra-driver-core + + + + + org.xerial.snappy + snappy-java + 1.1.1-M1 + + + + net.jpountz.lz4 + lz4 + 1.2.0 + + + + com.googlecode.jcsv + jcsv + 1.4.0 + + + + org.slf4j + slf4j-log4j12 + test + + + + + + diff --git a/auth/auth-cass/src/main/cql/.gitignore b/auth/auth-cass/src/main/cql/.gitignore new file mode 100644 index 00000000..f17048e9 --- /dev/null +++ b/auth/auth-cass/src/main/cql/.gitignore @@ -0,0 +1 @@ +/init.cql diff --git a/auth/auth-cass/src/main/cql/keyspace.cql b/auth/auth-cass/src/main/cql/keyspace.cql new file mode 100644 index 00000000..ad58090f --- /dev/null +++ b/auth/auth-cass/src/main/cql/keyspace.cql @@ -0,0 +1,9 @@ +// For Developer Machine single instance +CREATE KEYSPACE authz + WITH REPLICATION = {'class' : 'SimpleStrategy','replication_factor':1}; +// +// + +// Example of Network Topology, with Datacenter dc1 & dc2 +// CREATE KEYSPACE authz WITH replication = { 'class': 'NetworkTopologyStrategy', 'dc1': '2', 'dc2': '2' }; +// diff --git a/auth/auth-cass/src/main/cql/osaaf.cql b/auth/auth-cass/src/main/cql/osaaf.cql new file mode 100644 index 00000000..83c7fdf0 --- /dev/null +++ b/auth/auth-cass/src/main/cql/osaaf.cql @@ -0,0 +1,61 @@ +USE authz; + +// Create 'org' root NS +INSERT INTO ns (name,description,parent,scope,type) + VALUES('org','Root Namespace','.',1,1); + +INSERT INTO role(ns, name, perms, description) + VALUES('org','admin',{'org.access|*|*'},'Org Admins'); + +INSERT INTO role(ns, name, perms, description) + VALUES('org','owner',{'org.access|*|read,approve'},'Org Owners'); + +INSERT INTO perm(ns, type, instance, action, roles, description) + VALUES ('org','access','*','read,approve',{'org.owner'},'Org Read Access'); + +INSERT INTO perm(ns, type, instance, action, roles, description) + VALUES ('org','access','*','*',{'org.admin'},'Org Write Access'); + +// Create Root pass +INSERT INTO cred (id,ns,type,cred,expires) + VALUES ('initial@osaaf.org','org.osaaf',1,0x008c5926ca861023c1d2a36653fd88e2,'2099-12-31') using TTL 14400; + +INSERT INTO user_role(user,role,expires,ns,rname) + VALUES ('initial@osaaf.org','org.admin','2099-12-31','org','admin') using TTL 14400; + + +// Create org.osaaf +INSERT INTO ns (name,description,parent,scope,type) + VALUES('org.osaaf','OSAAF Namespace','org',2,2); + +INSERT INTO role(ns, name, perms,description) + VALUES('org.osaaf','admin',{'org.osaaf.access|*|*'},'OSAAF Admins'); + +INSERT INTO perm(ns, type, instance, action, roles,description) + VALUES ('org.osaaf','access','*','*',{'org.osaaf.admin'},'OSAAF Write Access'); + +INSERT INTO role(ns, name, perms,description) + VALUES('org.osaaf','owner',{'org.osaaf.access|*|read,approve'},'OSAAF Owners'); + +INSERT INTO perm(ns, type, instance, action, roles,description) + VALUES ('org.osaaf','access','*','read,appove',{'org.osaaf.owner'},'OSAAF Read Access'); + +// Create org.osaaf.aaf +INSERT INTO ns (name,description,parent,scope,type) + VALUES('org.osaaf.aaf','Application Authorization Framework','org.osaaf',3,3); + +INSERT INTO role(ns, name, perms, description) + VALUES('org.osaaf.aaf','admin',{'org.osaaf.aaf.access|*|*'},'AAF Admins'); + +INSERT INTO perm(ns, type, instance, action, roles, description) + VALUES ('org.osaaf.aaf','access','*','*',{'org.osaaf.aaf.admin'},'AAF Write Access'); + +INSERT INTO perm(ns, type, instance, action, roles, description) + VALUES ('org.osaaf.aaf','access','*','read,approve',{'org.osaaf.aaf.owner'},'AAF Read Access'); + +INSERT INTO role(ns, name, perms, description) + VALUES('org.osaaf.aaf','owner',{'org.osaaf.aaf.access|*|read,approve'},'AAF Owners'); + +INSERT INTO user_role(user,role,expires,ns,rname) + VALUES ('initial@osaaf.org','org.osaaf.aaf.admin','2099-12-31','org.osaaf.aaf','admin') using TTL 14400; + diff --git a/auth/auth-cass/src/main/cql/temp_identity.cql b/auth/auth-cass/src/main/cql/temp_identity.cql new file mode 100644 index 00000000..ba6e7828 --- /dev/null +++ b/auth/auth-cass/src/main/cql/temp_identity.cql @@ -0,0 +1,8 @@ +USE authz; + +INSERT INTO user_role(user,role,expires,ns,rname) + VALUES ('jonathan@people.osaaf.org','org.admin','2099-12-31','org','admin') ; + +INSERT INTO user_role(user,role,expires,ns,rname) + VALUES ('jonathan@people.osaaf.org','org.osaaf.aaf.admin','2099-12-31','org.osaaf.aaf','admin') ; + diff --git a/auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/AbsCassDAO.java b/auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/AbsCassDAO.java new file mode 100644 index 00000000..9794b2e5 --- /dev/null +++ b/auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/AbsCassDAO.java @@ -0,0 +1,504 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.dao; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Deque; +import java.util.List; +import java.util.concurrent.ConcurrentLinkedDeque; + +import org.onap.aaf.auth.dao.cass.Status; +import org.onap.aaf.auth.layer.Result; +import org.onap.aaf.misc.env.APIException; +import org.onap.aaf.misc.env.Env; +import org.onap.aaf.misc.env.TimeTaken; +import org.onap.aaf.misc.env.TransStore; + +import com.datastax.driver.core.BoundStatement; +import com.datastax.driver.core.Cluster; +import com.datastax.driver.core.ConsistencyLevel; +import com.datastax.driver.core.PreparedStatement; +import com.datastax.driver.core.ResultSet; +import com.datastax.driver.core.ResultSetFuture; +import com.datastax.driver.core.Row; +import com.datastax.driver.core.Session; +import com.datastax.driver.core.exceptions.DriverException; + +public abstract class AbsCassDAO { + protected static final char DOT = '.'; + protected static final char DOT_PLUS_ONE = '.'+1; + protected static final String FIRST_CHAR = Character.toString((char)0); + protected static final String LAST_CHAR = Character.toString((char)Character.MAX_VALUE); + protected static final int FIELD_COMMAS = 0; + protected static final int QUESTION_COMMAS = 1; + protected static final int ASSIGNMENT_COMMAS = 2; + protected static final int WHERE_ANDS = 3; + + private Cluster cluster; + /* + * From DataStax + * com.datastax.driver.core.Session + A session holds connections to a Cassandra cluster, allowing it to be queried. Each session maintains multiple connections to the cluster nodes, + provides policies to choose which node to use for each query (round-robin on all nodes of the cluster by default), and handles retries for + failed query (when it makes sense), etc... + Session instances are thread-safe and usually a single instance is enough per application. However, a given session can only be set to one + keyspace at a time, so one instance per keyspace is necessary. + */ + private Session session; + private final String keyspace; + // If this is null, then we own session + private final AbsCassDAO owningDAO; + protected Class dataClass; + private final String name; +// private static Slot sessionSlot; // not used since 2015 + private static final ArrayList.PSInfo> psinfos = new ArrayList.PSInfo>(); + private static final List EMPTY = new ArrayList(0); + private static final Deque resetDeque = new ConcurrentLinkedDeque(); + private static boolean resetTrigger = false; + private static long nextAvailableReset = 0; + + public AbsCassDAO(TRANS trans, String name, Cluster cluster, String keyspace, Class dataClass) { + this.name = name; + this.cluster = cluster; + this.keyspace = keyspace; + owningDAO = null; // we own session + session = null; + this.dataClass = dataClass; + } + + public AbsCassDAO(TRANS trans, String name, AbsCassDAO aDao, Class dataClass) { + this.name = name; + cluster = aDao.cluster; + keyspace = aDao.keyspace; + session = null; + // We do not own session + owningDAO = aDao; + this.dataClass = dataClass; + } + +// Not used since 2015 +// public static void setSessionSlot(Slot slot) { +// sessionSlot = slot; +// } + + //Note: Lower case ON PURPOSE. These names used to create History Messages + public enum CRUD { + create,read,update,delete; + } + + public class PSInfo { + private PreparedStatement ps; + private final int size; + private final Loader loader; + private final CRUD crud; // Store CRUD, because it makes a difference in Object Order, see Loader + private final String cql; + private final ConsistencyLevel consistency; + + + /** + * Create a PSInfo and create Prepared Statement + * + * @param trans + * @param theCQL + * @param loader + */ + public PSInfo(TRANS trans, String theCQL, Loader loader, ConsistencyLevel consistency) { + this.loader = loader; + this.consistency=consistency; + psinfos.add(this); + + cql = theCQL.trim().toUpperCase(); + if(cql.startsWith("INSERT")) { + crud = CRUD.create; + } else if(cql.startsWith("UPDATE")) { + crud = CRUD.update; + } else if(cql.startsWith("DELETE")) { + crud = CRUD.delete; + } else { + crud = CRUD.read; + } + + int idx = 0, count=0; + while((idx=cql.indexOf('?',idx))>=0) { + ++idx; + ++count; + } + size=count; + } + + public synchronized void reset() { + ps = null; + } + + private synchronized BoundStatement ps(TransStore trans) throws APIException, IOException { + /* From Datastax + You should prepare only once, and cache the PreparedStatement in your application (it is thread-safe). + If you call prepare multiple times with the same query string, the driver will log a warning. + */ + if(ps==null) { + TimeTaken tt = trans.start("Preparing PSInfo " + crud.toString().toUpperCase() + " on " + name,Env.SUB); + try { + ps = getSession(trans).prepare(cql); + ps.setConsistencyLevel(consistency); + } catch (DriverException e) { + reportPerhapsReset(trans,e); + throw e; + } finally { + tt.done(); + } + } + // BoundStatements are NOT threadsafe... need a new one each time. + return new BoundStatement(ps); + } + + /** + * Execute a Prepared Statement by extracting from DATA object + * + * @param trans + * @param text + * @param data + * @return + */ + public Result execAsync(TRANS trans, String text, DATA data) { + TimeTaken tt = trans.start(text, Env.REMOTE); + try { + return Result.ok(getSession(trans).executeAsync( + ps(trans).bind(loader.extract(data, size, crud)))); + } catch (DriverException | APIException | IOException e) { + AbsCassDAO.this.reportPerhapsReset(trans,e); + return Result.err(Status.ERR_Backend,"%s-%s executing %s",e.getClass().getName(),e.getMessage(), cql); + } finally { + tt.done(); + } + } + + /** + * Execute a Prepared Statement on Object[] key + * + * @param trans + * @param text + * @param objs + * @return + */ + public Result execAsync(TRANS trans, String text, Object ... objs) { + TimeTaken tt = trans.start(text, Env.REMOTE); + try { + return Result.ok(getSession(trans).executeAsync(ps(trans).bind(objs))); + } catch (DriverException | APIException | IOException e) { + AbsCassDAO.this.reportPerhapsReset(trans,e); + return Result.err(Status.ERR_Backend,"%s-%s executing %s",e.getClass().getName(),e.getMessage(), cql); + } finally { + tt.done(); + } + } + + /* + * Note: + * + */ + + /** + * Execute a Prepared Statement by extracting from DATA object + * + * @param trans + * @param text + * @param data + * @return + */ + public Result exec(TRANS trans, String text, DATA data) { + TimeTaken tt = trans.start(text, Env.REMOTE); + try { + /* + * "execute" (and executeAsync) + * Executes the provided query. + This method blocks until at least some result has been received from the database. However, + for SELECT queries, it does not guarantee that the result has been received in full. But it + does guarantee that some response has been received from the database, and in particular + guarantee that if the request is invalid, an exception will be thrown by this method. + + Parameters: + statement - the CQL query to execute (that can be any Statement). + Returns: + the result of the query. That result will never be null but can be empty (and will + be for any non SELECT query). + */ + return Result.ok(getSession(trans).execute( + ps(trans).bind(loader.extract(data, size, crud)))); + } catch (DriverException | APIException | IOException e) { + AbsCassDAO.this.reportPerhapsReset(trans,e); + return Result.err(Status.ERR_Backend,"%s-%s executing %s",e.getClass().getName(),e.getMessage(), cql); + } finally { + tt.done(); + } + } + + /** + * Execute a Prepared Statement on Object[] key + * + * @param trans + * @param text + * @param objs + * @return + */ + public Result exec(TRANS trans, String text, Object ... objs) { + TimeTaken tt = trans.start(text, Env.REMOTE); + try { + return Result.ok(getSession(trans).execute(ps(trans).bind(objs))); + } catch (DriverException | APIException | IOException e) { + AbsCassDAO.this.reportPerhapsReset(trans,e); + return Result.err(Status.ERR_Backend,"%s-%s executing %s",e.getClass().getName(),e.getMessage(), cql); + } finally { + tt.done(); + } + } + + /** + * Read the Data from Cassandra given a Prepared Statement (defined by the + * DAO Instance) + * + * This is common behavior among all DAOs. + * @throws DAOException + */ + public Result> read(TRANS trans, String text, Object[] key) { + TimeTaken tt = trans.start(text,Env.REMOTE); + + ResultSet rs; + try { + rs = getSession(trans).execute(key==null?ps(trans):ps(trans).bind(key)); +/// TEST CODE for Exception +// boolean force = true; +// if(force) { +// Map misa = new HashMap(); +// //misa.put(new InetSocketAddress(444),new Exception("no host was tried")); +// misa.put(new InetSocketAddress(444),new Exception("Connection has been closed")); +// throw new com.datastax.driver.core.exceptions.NoHostAvailableException(misa); +//// throw new com.datastax.driver.core.exceptions.AuthenticationException(new InetSocketAddress(9999),"no host was tried"); +// } +//// END TEST CODE + } catch (DriverException | APIException | IOException e) { + AbsCassDAO.this.reportPerhapsReset(trans,e); + return Result.err(Status.ERR_Backend,"%s-%s executing %s",e.getClass().getName(),e.getMessage(), cql); + } finally { + tt.done(); + } + + return extract(loader,rs,null /*let Array be created if necessary*/,dflt); + } + + public Result> read(TRANS trans, String text, DATA data) { + return read(trans,text, loader.extract(data, size, crud)); + } + + public Object[] keyFrom(DATA data) { + return loader.extract(data, size, CRUD.delete); // Delete is key only + } + + /* + * Note: in case PSInfos are deleted, we want to remove them from list. This is not expected, + * but we don't want a data leak if it does. Finalize doesn't have to happen quickly + */ + @Override + protected void finalize() throws Throwable { + psinfos.remove(this); + } + } + + protected final Accept dflt = new Accept() { + @Override + public boolean ok(DATA data) { + return true; + } + }; + + + @SuppressWarnings("unchecked") + protected final Result> extract(Loader loader, ResultSet rs, List indata, Accept accept) { + List rows = rs.all(); + if(rows.isEmpty()) { + return Result.ok((List)EMPTY); // Result sets now .emptyList(true); + } else { + DATA d; + List data = indata==null?new ArrayList(rows.size()):indata; + + for(Row row : rows) { + try { + d = loader.load(dataClass.newInstance(),row); + if(accept.ok(d)) { + data.add(d); + } + } catch(Exception e) { + return Result.err(e); + } + } + return Result.ok(data); + } + } + + private static final String NEW_CASSANDRA_SESSION_CREATED = "New Cassandra Session Created"; + private static final String NEW_CASSANDRA_CLUSTER_OBJECT_CREATED = "New Cassandra Cluster Object Created"; + private static final String NEW_CASSANDRA_SESSION = "New Cassandra Session"; + + private static class ResetRequest { + //package on purpose + Session session; + long timestamp; + + public ResetRequest(Session session) { + this.session = session; + timestamp = System.currentTimeMillis(); + } + } + + + public static final void primePSIs(TransStore trans) throws APIException, IOException { + for(AbsCassDAO.PSInfo psi : psinfos) { + if(psi.ps==null) { + psi.ps(trans); + } + } + } + + public final Session getSession(TransStore trans) throws APIException, IOException { + // SessionFilter unused since 2015 + // Try to use Trans' session, if exists +// if(sessionSlot!=null) { // try to get from Trans +// Session sess = trans.get(sessionSlot, null); +// if(sess!=null) { +// return sess; +// } +// } + + // If there's an owning DAO, use it's session + if(owningDAO!=null) { + return owningDAO.getSession(trans); + } + + // OK, nothing else works... get our own. + if(session==null || resetTrigger) { + Cluster tempCluster = null; + Session tempSession = null; + try { + synchronized(NEW_CASSANDRA_SESSION_CREATED) { + boolean reset = false; + for(ResetRequest r : resetDeque) { + if(r.session == session) { + if(r.timestamp>nextAvailableReset) { + reset=true; + nextAvailableReset = System.currentTimeMillis() + 60000; + tempCluster = cluster; + tempSession = session; + break; + } else { + trans.warn().log("Cassandra Connection Reset Ignored: Recent Reset"); + } + } + } + + if(reset || session == null) { + TimeTaken tt = trans.start(NEW_CASSANDRA_SESSION, Env.SUB); + try { + // Note: Maitrayee recommended not closing the cluster, just + // overwrite it. Jonathan 9/30/2016 assuming same for Session + // This was a bad idea. Ran out of File Handles as I suspected, Jonathan + if(reset) { + for(AbsCassDAO.PSInfo psi : psinfos) { + psi.reset(); + } + } + if(reset || cluster==null) { + cluster = CassAccess.cluster(trans, keyspace); + trans.warn().log(NEW_CASSANDRA_CLUSTER_OBJECT_CREATED); + } + if(reset || session==null) { + session = cluster.connect(keyspace); + trans.warn().log(NEW_CASSANDRA_SESSION_CREATED); + } + } finally { + resetTrigger=false; + tt.done(); + } + } + } + } finally { + TimeTaken tt = trans.start("Clear Reset Deque", Env.SUB); + try { + resetDeque.clear(); + // Not clearing Session/Cluster appears to kill off FileHandles + if(tempSession!=null && !tempSession.isClosed()) { + tempSession.close(); + } + if(tempCluster!=null && !tempCluster.isClosed()) { + tempCluster.close(); + } + } finally { + tt.done(); + } + } + } + return session; + } + + public final boolean reportPerhapsReset(TransStore trans, Exception e) { + if(owningDAO!=null) { + return owningDAO.reportPerhapsReset(trans, e); + } else { + boolean rv = false; + if(CassAccess.isResetException(e)) { + trans.warn().printf("Session Reset called for %s by %s ",session==null?"":session,e==null?"Mgmt Command":e.getClass().getName()); + resetDeque.addFirst(new ResetRequest(session)); + rv = resetTrigger = true; + } + trans.error().log(e); + return rv; + } + } + + public void close(TransStore trans) { + if(owningDAO==null) { + if(session!=null) { + TimeTaken tt = trans.start("Cassandra Session Close", Env.SUB); + try { + session.close(); + } finally { + tt.done(); + } + session = null; + } else { + trans.debug().log("close called(), Session already closed"); + } + } else { + owningDAO.close(trans); + } + } + + protected void wasModified(TRANS trans, CRUD modified, DATA data, String ... override) { + } + + protected interface Accept { + public boolean ok(DATA data); + } + +} + + + diff --git a/auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/Bytification.java b/auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/Bytification.java new file mode 100644 index 00000000..279f399d --- /dev/null +++ b/auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/Bytification.java @@ -0,0 +1,30 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.dao; + +import java.io.IOException; +import java.nio.ByteBuffer; + +public interface Bytification { + public ByteBuffer bytify() throws IOException; + public void reconstitute(ByteBuffer bb) throws IOException; +} diff --git a/auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/CIDAO.java b/auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/CIDAO.java new file mode 100644 index 00000000..83b13c34 --- /dev/null +++ b/auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/CIDAO.java @@ -0,0 +1,50 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.dao; + +import java.util.Date; + +import org.onap.aaf.auth.layer.Result; +import org.onap.aaf.misc.env.Trans; + +public interface CIDAO { + + /** + * Touch the date field for given Table + * + * @param trans + * @param name + * @return + */ + public abstract Result touch(TRANS trans, String name, int ... seg); + + /** + * Read all Info entries, and set local Date objects + * + * This is to support regular data checks on the Database to speed up Caching behavior + * + */ + public abstract Result check(TRANS trans); + + public abstract Date get(TRANS trans, String table, int seg); + +} \ No newline at end of file diff --git a/auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/Cacheable.java b/auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/Cacheable.java new file mode 100644 index 00000000..d697b90e --- /dev/null +++ b/auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/Cacheable.java @@ -0,0 +1,34 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.dao; +/** + * Interface to obtain Segment Integer from DAO Data + * for use in Caching mechanism + * + * This should typically be obtained by getting the Hash of the key, then using modulus on the size of segment. + * + * @author Jonathan + * + */ +public interface Cacheable { + public int[] invalidate(Cached cache); +} diff --git a/auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/Cached.java b/auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/Cached.java new file mode 100644 index 00000000..0797b041 --- /dev/null +++ b/auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/Cached.java @@ -0,0 +1,199 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.dao; + +import java.util.Date; +import java.util.List; +import java.util.Map; +import java.util.Timer; +import java.util.TimerTask; + +import org.onap.aaf.auth.cache.Cache; +import org.onap.aaf.auth.dao.cass.Status; +import org.onap.aaf.auth.env.AuthzEnv; +import org.onap.aaf.auth.env.AuthzTrans; +import org.onap.aaf.auth.layer.Result; +import org.onap.aaf.misc.env.Env; +import org.onap.aaf.misc.env.Trans; + +public class Cached extends Cache { + // Java does not allow creation of Arrays with Generics in them... + // private Map cache[]; + protected final CIDAO info; + + private static Timer infoTimer; + private Object cache[]; + public final int segSize; + + protected final String name; + + private final long expireIn; + + + + // Taken from String Hash, but coded, to ensure consistent across Java versions. Also covers negative case; + public int cacheIdx(String key) { + int h = 0; + for (int i = 0; i < key.length(); i++) { + h = 31*h + key.charAt(i); + } + if(h<0)h*=-1; + return h%segSize; + } + + public Cached(CIDAO info, String name, int segSize, long expireIn) { + this.name =name; + this.segSize = segSize; + this.info = info; + this.expireIn = expireIn; + cache = new Object[segSize]; + // Create a new Map for each Segment, and store locally + for(int i=0;i data) { + @SuppressWarnings("unchecked") + Map map = ((Map)cache[cacheIdx(key)]); + map.put(key, new Dated(data, expireIn)); + } + + + public int invalidate(String key) { + int cacheIdx = cacheIdx(key); + @SuppressWarnings("unchecked") + Map map = ((Map)cache[cacheIdx]); +// if(map.remove(key)!=null) // Not seeming to remove all the time + if(map!=null)map.clear(); +// System.err.println("Remove " + name + " " + key); + return cacheIdx; + } + + public Result invalidate(int segment) { + if(segment<0 || segment>=cache.length) return Result.err(Status.ERR_BadData,"Cache Segment %s is out of range",Integer.toString(segment)); + @SuppressWarnings("unchecked") + Map map = ((Map)cache[segment]); + if(map!=null) { + map.clear(); + } + return Result.ok(); + } + + protected interface Getter { + public abstract Result> get(); + }; + + // TODO utilize Segmented Caches, and fold "get" into "reads" + @SuppressWarnings("unchecked") + public Result> get(TRANS trans, String key, Getter getter) { + List ld = null; + Result> rld = null; + + int cacheIdx = cacheIdx(key); + Map map = ((Map)cache[cacheIdx]); + + // Check for saved element in cache + Dated cached = map.get(key); + // Note: These Segment Timestamps are kept up to date with DB + Date dbStamp = info.get(trans, name,cacheIdx); + + // Check for cache Entry and whether it is still good (a good Cache Entry is same or after DBEntry, so we use "before" syntax) + if(cached!=null && dbStamp.before(cached.timestamp)) { + ld = (List)cached.data; + rld = Result.ok(ld); + } else { + rld = getter.get(); + if(rld.isOK()) { // only store valid lists + map.put(key, new Dated(rld.value,expireIn)); // successful item found gets put in cache +// } else if(rld.status == Result.ERR_Backend){ +// map.remove(key); + } + } + return rld; + } + + /** + * Each Cached object has multiple Segments that need cleaning. Derive each, and add to Cleansing Thread + * @param env + * @param dao + */ + public static void startCleansing(AuthzEnv env, CachedDAO ... dao) { + for(CachedDAO d : dao) { + for(int i=0;i void startRefresh(AuthzEnv env, CIDAO cidao) { + if(infoTimer==null) { + infoTimer = new Timer("CachedDAO Info Refresh Timer"); + int minRefresh = 10*1000*60; // 10 mins Integer.parseInt(env.getProperty(CACHE_MIN_REFRESH_INTERVAL,"2000")); // 2 second minimum refresh + infoTimer.schedule(new Refresh(env,cidao, minRefresh), 1000, minRefresh); // note: Refresh from DB immediately + } + } + + public static void stopTimer() { + Cache.stopTimer(); + if(infoTimer!=null) { + infoTimer.cancel(); + infoTimer = null; + } + } + + private final static class Refresh extends TimerTask { + private static final int maxRefresh = 2*60*10000; // 20 mins + private AuthzEnv env; + private CIDAO cidao; + private int minRefresh; + private long lastRun; + + public Refresh(AuthzEnv env, CIDAO cidao, int minRefresh) { + this.env = env; + this.cidao = cidao; + this.minRefresh = minRefresh; + lastRun = System.currentTimeMillis()-maxRefresh-1000; + } + + @Override + public void run() { + // Evaluate whether to refresh based on transaction rate + long now = System.currentTimeMillis(); + long interval = now-lastRun; + + if(interval < minRefresh || interval < Math.min(env.transRate(),maxRefresh)) return; + lastRun = now; + AuthzTrans trans = env.newTransNoAvg(); + Result rv = cidao.check(trans); + if(rv.status!=Result.OK) { + env.error().log("Error in CacheInfo Refresh",rv.details); + } + if(env.debug().isLoggable()) { + StringBuilder sb = new StringBuilder("Cache Info Refresh: "); + trans.auditTrail(0, sb, Env.REMOTE); + env.debug().log(sb); + } + } + } +} diff --git a/auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/CachedDAO.java b/auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/CachedDAO.java new file mode 100644 index 00000000..017f8780 --- /dev/null +++ b/auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/CachedDAO.java @@ -0,0 +1,228 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.dao; + +import java.util.ArrayList; +import java.util.List; + +import org.onap.aaf.auth.dao.cass.Status; +import org.onap.aaf.auth.layer.Result; +import org.onap.aaf.misc.env.Trans; + +/** + * CachedDAO + * + * Cache the response of "get" of any DAO. + * + * For simplicity's sake, at this time, we only do this for single Object keys + * + * @author Jonathan + * + * @param + */ +public class CachedDAO,DATA extends Cacheable> + extends Cached implements DAO_RO{ +// private final String dirty_str; + + private final D dao; + + public CachedDAO(D dao, CIDAO info, int segsize, long expireIn) { + super(info, dao.table(), segsize, expireIn); + + // Instantiate a new Cache per DAO name (so separate instances use the same cache) + this.dao = dao; + //read_str = "Cached READ for " + dao.table(); +// dirty_str = "Cache DIRTY on " + dao.table(); + if(dao instanceof CassDAOImpl) { + ((CassDAOImpl)dao).cache = this; + } + } + + public static, DT extends Cacheable> + CachedDAO create(DA dao, CIDAO info, int segsize, long expireIn) { + return new CachedDAO(dao,info, segsize, expireIn); + } + + public void add(DATA data) { + String key = keyFromObjs(dao.keyFrom(data)); + List list = new ArrayList(); + list.add(data); + super.add(key,list); + } + +// public void invalidate(TRANS trans, Object ... objs) { +// TimeTaken tt = trans.start(dirty_str, Env.SUB); +// try { +// super.invalidate(keyFromObjs(objs)); +// } finally { +// tt.done(); +// } +// } + + public static String keyFromObjs(Object ... objs) { + String key; + if(objs.length==1 && objs[0] instanceof String) { + key = (String)objs[0]; + } else { + StringBuilder sb = new StringBuilder(); + boolean first = true; + for(Object o : objs) { + if(o!=null) { + if(first) { + first =false; + } else { + sb.append('|'); + } + sb.append(o.toString()); + } + } + key = sb.toString(); + } + return key; + } + + public Result create(TRANS trans, DATA data) { + Result d = dao.create(trans,data); + if(d.status==Status.OK) { + add(d.value); + } else { + trans.error().log(d.errorString()); + } + // dao.create already modifies cache. Do not invalidate again. invalidate(trans,data); + return d; + } + + protected class DAOGetter implements Getter { + protected TRANS trans; + protected Object objs[]; + protected D dao; + public Result> result; + + public DAOGetter(TRANS trans, D dao, Object ... objs) { + this.trans = trans; + this.dao = dao; + this.objs = objs; + } + + /** + * Separated into single call for easy overloading + * @return + */ + public Result> call() { + return dao.read(trans, objs); + } + + @Override + public final Result> get() { + return call(); +// if(result.isOKhasData()) { // Note, given above logic, could exist, but stale +// return result.value; +// } else { +// return null; +// } + } + } + + @Override + public Result> read(final TRANS trans, final Object ... objs) { + DAOGetter getter = new DAOGetter(trans,dao,objs); + return get(trans, keyFromObjs(objs),getter); +// if(ld!=null) { +// return Result.ok(ld);//.emptyList(ld.isEmpty()); +// } +// // Result Result if exists +// if(getter.result==null) { +// return Result.err(Status.ERR_NotFound, "No Cache or Lookup found on [%s]",dao.table()); +// } +// return getter.result; + } + + // Slight Improved performance available when String and Obj versions are known. + public Result> read(final String key, final TRANS trans, final Object[] objs) { + DAOGetter getter = new DAOGetter(trans,dao,objs); + return get(trans, key, getter); +// if(ld!=null) { +// return Result.ok(ld);//.emptyList(ld.isEmpty()); +// } +// // Result Result if exists +// if(getter.result==null) { +// return Result.err(Status.ERR_NotFound, "No Cache or Lookup found on [%s]",dao.table()); +// } +// return getter.result; + } + + @Override + public Result> read(TRANS trans, DATA data) { + return read(trans,dao.keyFrom(data)); + } + public Result update(TRANS trans, DATA data) { + Result d = dao.update(trans, data); + if(d.status==Status.OK) { + add(data); + } else { + trans.error().log(d.errorString()); + } + return d; + } + + public Result delete(TRANS trans, DATA data, boolean reread) { + if(reread) { // If reread, get from Cache, if possible, not DB exclusively + Result> rd = read(trans,data); + if(rd.notOK()) { + return Result.err(rd); +// } else { +// trans.error().log(rd.errorString()); + } + if(rd.isEmpty()) { + data.invalidate(this); + return Result.err(Status.ERR_NotFound,"Not Found"); + } + data = rd.value.get(0); + } + Result rv=dao.delete(trans, data, false); + data.invalidate(this); + return rv; + } + + @Override + public void close(TRANS trans) { + if(dao!=null) { + dao.close(trans); + } + } + + + @Override + public String table() { + return dao.table(); + } + + public D dao() { + return dao; + } + + public void invalidate(TRANS trans, DATA data) { + if(info.touch(trans, dao.table(),data.invalidate(this)).notOK()) { + trans.error().log("Cannot touch CacheInfo for Role"); + } + } +} diff --git a/auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/CassAccess.java b/auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/CassAccess.java new file mode 100644 index 00000000..e70bffb7 --- /dev/null +++ b/auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/CassAccess.java @@ -0,0 +1,223 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.dao; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +import org.onap.aaf.auth.env.AuthzEnv; +import org.onap.aaf.cadi.config.Config; +import org.onap.aaf.cadi.routing.GreatCircle; +import org.onap.aaf.misc.env.APIException; +import org.onap.aaf.misc.env.Env; +import org.onap.aaf.misc.env.util.Split; + +import com.datastax.driver.core.Cluster; +import com.datastax.driver.core.Cluster.Builder; +import com.datastax.driver.core.policies.DCAwareRoundRobinPolicy; +import com.datastax.driver.core.policies.TokenAwarePolicy; + +public class CassAccess { + public static final String KEYSPACE = "authz"; + public static final String CASSANDRA_CLUSTERS = "cassandra.clusters"; + public static final String CASSANDRA_CLUSTERS_PORT = "cassandra.clusters.port"; + public static final String CASSANDRA_CLUSTERS_USER_NAME = "cassandra.clusters.user"; + public static final String CASSANDRA_CLUSTERS_PASSWORD = "cassandra.clusters.password"; + public static final String CASSANDRA_RESET_EXCEPTIONS = "cassandra.reset.exceptions"; + private static final List resetExceptions = new ArrayList(); + public static final String ERR_ACCESS_MSG = "Accessing Backend"; + private static Builder cb = null; + + /** + * To create DCAwareRoundRobing Policy: + * Need Properties + * LATITUDE (or AFT_LATITUDE) + * LONGITUDE (or AFT_LONGITUDE) + * CASSANDRA CLUSTERS with additional information: + * machine:DC:lat:long,machine:DC:lat:long + * @param env + * @param prefix + * @return + * @throws APIException + * @throws IOException + */ + +// @SuppressWarnings("deprecation") + public static synchronized Cluster cluster(Env env, String prefix) throws APIException, IOException { + if(cb == null) { + String pre; + if(prefix==null) { + pre=""; + } else { + env.info().log("Cassandra Connection for ",prefix); + pre = prefix+'.'; + } + cb = Cluster.builder(); + String str = env.getProperty(pre+CASSANDRA_CLUSTERS_PORT,env.getProperty(CASSANDRA_CLUSTERS_PORT,"9042")); + if(str!=null) { + env.init().log("Cass Port = ",str ); + cb.withPort(Integer.parseInt(str)); + } + str = env.getProperty(pre+CASSANDRA_CLUSTERS_USER_NAME,env.getProperty(CASSANDRA_CLUSTERS_USER_NAME,null)); + if(str!=null) { + env.init().log("Cass User = ",str ); + String epass = env.getProperty(pre + CASSANDRA_CLUSTERS_PASSWORD,env.getProperty(CASSANDRA_CLUSTERS_PASSWORD,null)); + if(epass==null) { + throw new APIException("No Password configured for " + str); + } + //TODO Figure out way to ensure Decryptor setting in AuthzEnv + if(env instanceof AuthzEnv) { + cb.withCredentials(str,((AuthzEnv)env).decrypt(epass,true)); + } else { + cb.withCredentials(str, env.decryptor().decrypt(epass)); + } + } + + str = env.getProperty(pre+CASSANDRA_RESET_EXCEPTIONS,env.getProperty(CASSANDRA_RESET_EXCEPTIONS,null)); + if(str!=null) { + env.init().log("Cass ResetExceptions = ",str ); + for(String ex : Split.split(',', str)) { + resetExceptions.add(new Resettable(env,ex)); + } + } + + str = env.getProperty(Config.CADI_LATITUDE); + Double lat = str!=null?Double.parseDouble(str):null; + str = env.getProperty(Config.CADI_LONGITUDE); + Double lon = str!=null?Double.parseDouble(str):null; + if(lat == null || lon == null) { + throw new APIException(Config.CADI_LATITUDE + " and/or " + Config.CADI_LONGITUDE + " are not set"); + } + + env.init().printf("Service Latitude,Longitude = %f,%f",lat,lon); + + str = env.getProperty(pre+CASSANDRA_CLUSTERS,env.getProperty(CASSANDRA_CLUSTERS,"localhost")); + env.init().log("Cass Clusters = ",str ); + String[] machs = Split.split(',', str); + String[] cpoints = new String[machs.length]; + String bestDC = null; + int numInBestDC = 1; + double mlat, mlon,temp,distance = Double.MAX_VALUE; + for(int i=0;i0) { + cpoints[i]=minfo[0]; + } + + if(minfo.length>3) { + if(minfo[1].equals(bestDC)) { + ++numInBestDC; + } else { + // Calc closest DC with Great Circle + mlat = Double.parseDouble(minfo[2]); + mlon = Double.parseDouble(minfo[3]); + // Note: GreatCircle Distance is always >= 0.0 (not negative) + if((temp=GreatCircle.calc(lat, lon, mlat, mlon)) < distance) { + distance = temp; + if(bestDC==null || !bestDC.equals(minfo[1])) { + bestDC = minfo[1]; + numInBestDC = 1; + } + } + } + } + } + + cb.addContactPoints(cpoints); + + if(bestDC!=null) { + // 8/26/2016 Management has determined that Accuracy is preferred over speed in bad situations + // Local DC Aware Load Balancing appears to have the highest normal performance, with the best + // Degraded Accuracy + DCAwareRoundRobinPolicy dcrrPolicy = DCAwareRoundRobinPolicy.builder() + .withLocalDc(bestDC) + .withUsedHostsPerRemoteDc(numInBestDC) + .build(); +// cb.withLoadBalancingPolicy(new DCAwareRoundRobinPolicy( +// bestDC, numInBestDC, true /*allow LocalDC to look at other DCs for LOCAL_QUORUM */)); + cb.withLoadBalancingPolicy(new TokenAwarePolicy(dcrrPolicy)); + env.init().printf("Cassandra configured for DCAwareRoundRobinPolicy with best DC at %s with emergency remote of up to %d node(s)" + ,bestDC, numInBestDC); + } else { + env.init().printf("Cassandra is using Default Policy, which is not DC aware"); + } + } + return cb.build(); + } + + private static class Resettable { + private Class cls; + private List messages; + + @SuppressWarnings("unchecked") + public Resettable(Env env, String propData) throws APIException { + if(propData!=null && propData.length()>1) { + String[] split = Split.split(':', propData); + if(split.length>0) { + try { + cls = (Class)Class.forName(split[0]); + } catch (ClassNotFoundException e) { + throw new APIException("Declared Cassandra Reset Exception, " + propData + ", cannot be ClassLoaded"); + } + } + if(split.length>1) { + messages=new ArrayList(); + for(int i=1;i + */ +public class CassDAOImpl extends AbsCassDAO implements DAO { + public static final String USER_NAME = "__USER_NAME__"; + protected static final String CREATE_SP = "CREATE "; + protected static final String UPDATE_SP = "UPDATE "; + protected static final String DELETE_SP = "DELETE "; + protected static final String SELECT_SP = "SELECT "; + + protected final String C_TEXT = getClass().getSimpleName() + " CREATE"; + protected final String R_TEXT = getClass().getSimpleName() + " READ"; + protected final String U_TEXT = getClass().getSimpleName() + " UPDATE"; + protected final String D_TEXT = getClass().getSimpleName() + " DELETE"; + private String table; + + protected final ConsistencyLevel readConsistency,writeConsistency; + + // Setteable only by CachedDAO + protected Cached cache; + + /** + * A Constructor from the originating Cluster. This DAO will open the Session at need, + * and shutdown the session when "close()" is called. + * + * @param cluster + * @param keyspace + * @param dataClass + */ + public CassDAOImpl(TRANS trans, String name, Cluster cluster, String keyspace, Class dataClass, String table, ConsistencyLevel read, ConsistencyLevel write) { + super(trans, name, cluster,keyspace,dataClass); + this.table = table; + readConsistency = read; + writeConsistency = write; + } + + /** + * A Constructor to share Session with other DAOs. + * + * This method get the Session and Cluster information from the calling DAO, and won't + * touch the Session on closure. + * + * @param aDao + * @param dataClass + */ + public CassDAOImpl(TRANS trans, String name, AbsCassDAO aDao, Class dataClass, String table, ConsistencyLevel read, ConsistencyLevel write) { + super(trans, name, aDao,dataClass); + this.table = table; + readConsistency = read; + writeConsistency = write; + } + + protected PSInfo createPS; + protected PSInfo readPS; + protected PSInfo updatePS; + protected PSInfo deletePS; + protected boolean async=false; + + public void async(boolean bool) { + async = bool; + } + + public final String[] setCRUD(TRANS trans, String table, Class dc,Loader loader) { + return setCRUD(trans, table, dc, loader, -1); + } + + public final String[] setCRUD(TRANS trans, String table, Class dc,Loader loader, int max) { + Field[] fields = dc.getDeclaredFields(); + int end = max>=0 & max0) { + for(int i=0;i0) { + sbfc.append(','); + sbq.append(','); + if(i=keylimit) { + if(i>keylimit) { + sbup.append(','); + } + sbup.append(fields[i].getName()); + sbup.append("=?"); + } + if(i create(TRANS trans, DATA data) { + if(createPS==null) { + Result.err(Result.ERR_NotImplemented,"Create is disabled for %s",getClass().getSimpleName()); + } + if(async) /*ResultSetFuture */ { + Result rs = createPS.execAsync(trans, C_TEXT, data); + if(rs.notOK()) { + return Result.err(rs); + } + } else { + Result rs = createPS.exec(trans, C_TEXT, data); + if(rs.notOK()) { + return Result.err(rs); + } + } + wasModified(trans, CRUD.create, data); + return Result.ok(data); + } + + /** + * Read the Unique Row associated with Full Keys + */ + public Result> read(TRANS trans, DATA data) { + if(readPS==null) { + Result.err(Result.ERR_NotImplemented,"Read is disabled for %s",getClass().getSimpleName()); + } + return readPS.read(trans, R_TEXT, data); + } + + public Result> read(TRANS trans, Object ... key) { + if(readPS==null) { + Result.err(Result.ERR_NotImplemented,"Read is disabled for %s",getClass().getSimpleName()); + } + return readPS.read(trans, R_TEXT, key); + } + + public Result readPrimKey(TRANS trans, Object ... key) { + if(readPS==null) { + Result.err(Result.ERR_NotImplemented,"Read is disabled for %s",getClass().getSimpleName()); + } + Result> rld = readPS.read(trans, R_TEXT, key); + if(rld.isOK()) { + if(rld.isEmpty()) { + return Result.err(Result.ERR_NotFound,rld.details); + } else { + return Result.ok(rld.value.get(0)); + } + } else { + return Result.err(rld); + } + } + + public Result update(TRANS trans, DATA data) { + return update(trans, data, async); + } + + public Result update(TRANS trans, DATA data, boolean async) { + if(updatePS==null) { + Result.err(Result.ERR_NotImplemented,"Update is disabled for %s",getClass().getSimpleName()); + } + if(async)/* ResultSet rs =*/ { + Result rs = updatePS.execAsync(trans, U_TEXT, data); + if(rs.notOK()) { + return Result.err(rs); + } + } else { + Result rs = updatePS.exec(trans, U_TEXT, data); + if(rs.notOK()) { + return Result.err(rs); + } + } + + wasModified(trans, CRUD.update, data); + return Result.ok(); + } + + // This method Sig for Cached... + public Result delete(TRANS trans, DATA data, boolean reread) { + if(deletePS==null) { + Result.err(Result.ERR_NotImplemented,"Delete is disabled for %s",getClass().getSimpleName()); + } + // Since Deleting will be stored off, for possible re-constitution, need the whole thing + if(reread) { + Result> rd = read(trans,data); + if(rd.notOK()) { + return Result.err(rd); + } + if(rd.isEmpty()) { + return Result.err(Status.ERR_NotFound,"Not Found"); + } + for(DATA d : rd.value) { + if(async) { + Result rs = deletePS.execAsync(trans, D_TEXT, d); + if(rs.notOK()) { + return Result.err(rs); + } + } else { + Result rs = deletePS.exec(trans, D_TEXT, d); + if(rs.notOK()) { + return Result.err(rs); + } + } + wasModified(trans, CRUD.delete, d); + } + } else { + if(async)/* ResultSet rs =*/ { + Result rs = deletePS.execAsync(trans, D_TEXT, data); + if(rs.notOK()) { + return Result.err(rs); + } + } else { + Result rs = deletePS.exec(trans, D_TEXT, data); + if(rs.notOK()) { + return Result.err(rs); + } + } + wasModified(trans, CRUD.delete, data); + } + return Result.ok(); + } + + public final Object[] keyFrom(DATA data) { + return createPS.keyFrom(data); + } + + @Override + public String table() { + return table; + } + + public static final String CASS_READ_CONSISTENCY="cassandra.readConsistency"; + public static final String CASS_WRITE_CONSISTENCY="cassandra.writeConsistency"; + protected static ConsistencyLevel readConsistency(AuthzTrans trans, String table) { + String prop = trans.getProperty(CASS_READ_CONSISTENCY+'.'+table); + if(prop==null) { + prop = trans.getProperty(CASS_READ_CONSISTENCY); + if(prop==null) { + return ConsistencyLevel.ONE; // this is Cassandra Default + } + } + return ConsistencyLevel.valueOf(prop); + } + + protected static ConsistencyLevel writeConsistency(AuthzTrans trans, String table) { + String prop = trans.getProperty(CASS_WRITE_CONSISTENCY+'.'+table); + if(prop==null) { + prop = trans.getProperty(CASS_WRITE_CONSISTENCY); + if(prop==null) { + return ConsistencyLevel.ONE; // this is Cassandra Default\ + } + } + return ConsistencyLevel.valueOf(prop); + } + + public static DataInputStream toDIS(ByteBuffer bb) { + byte[] b = bb.array(); + return new DataInputStream( + new ByteArrayInputStream(b,bb.position(),bb.limit()) + ); + } + + +} diff --git a/auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/DAO.java b/auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/DAO.java new file mode 100644 index 00000000..70db430e --- /dev/null +++ b/auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/DAO.java @@ -0,0 +1,44 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.dao; + +import org.onap.aaf.auth.layer.Result; +import org.onap.aaf.misc.env.Trans; + + +/** + * DataAccessObject Interface + * + * Extend the ReadOnly form (for Get), and add manipulation methods + * + * @author Jonathan + * + * @param + */ +public interface DAO extends DAO_RO { + public Result create(TRANS trans, DATA data); + public Result update(TRANS trans, DATA data); + // In many cases, the data has been correctly read first, so we shouldn't read again + // Use reread=true if you are using DATA with only a Key + public Result delete(TRANS trans, DATA data, boolean reread); + public Object[] keyFrom(DATA data); +} diff --git a/auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/DAOException.java b/auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/DAOException.java new file mode 100644 index 00000000..207576e4 --- /dev/null +++ b/auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/DAOException.java @@ -0,0 +1,51 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.dao; + +public class DAOException extends Exception { + + /** + * + */ + private static final long serialVersionUID = 1527904125585539823L; + +// // TODO - enum in result class == is our intended design, currently the DAO layer does not use Result so we still use these for now +// public final static DAOException RoleNotFoundDAOException = new DAOException("RoleNotFound"); +// public final static DAOException PermissionNotFoundDAOException = new DAOException("PermissionNotFound"); +// public final static DAOException UserNotFoundDAOException = new DAOException("UserNotFound"); + + public DAOException() { + } + + public DAOException(String message) { + super(message); + } + + public DAOException(Throwable cause) { + super(cause); + } + + public DAOException(String message, Throwable cause) { + super(message, cause); + } + +} diff --git a/auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/DAO_RO.java b/auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/DAO_RO.java new file mode 100644 index 00000000..4bffb5f3 --- /dev/null +++ b/auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/DAO_RO.java @@ -0,0 +1,70 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.dao; + +import java.util.List; + +import org.onap.aaf.auth.layer.Result; +import org.onap.aaf.misc.env.Trans; + +/** + * DataAccessObject - ReadOnly + * + * It is useful to have a ReadOnly part of the interface for CachedDAO + * + * Normal DAOs will implement full DAO + * + * @author Jonathan + * + * @param + */ +public interface DAO_RO { + /** + * Get a List of Data given Key of Object Array + * @param objs + * @return + * @throws DAOException + */ + public Result> read(TRANS trans, Object ... key); + + /** + * Get a List of Data given Key of DATA Object + * @param trans + * @param key + * @return + * @throws DAOException + */ + public Result> read(TRANS trans, DATA key); + + /** + * close DAO + */ + public void close(TRANS trans); + + /** + * Return name of referenced Data + * @return + */ + public String table(); + + +} diff --git a/auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/Loader.java b/auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/Loader.java new file mode 100644 index 00000000..485eabc6 --- /dev/null +++ b/auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/Loader.java @@ -0,0 +1,214 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.dao; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; + +import com.datastax.driver.core.Row; + +public abstract class Loader { + private int keylimit; + public Loader(int keylimit) { + this.keylimit = keylimit; + } + + public int keylimit() { + return keylimit; + } + + protected abstract DATA load(DATA data, Row row); + protected abstract void key(DATA data, int idx, Object[] obj); + protected abstract void body(DATA data, int idx, Object[] obj); + + public final Object[] extract(DATA data, int size, CassDAOImpl.CRUD type) { + Object[] rv=null; + switch(type) { + case delete: + rv = new Object[keylimit()]; + key(data,0,rv); + break; + case update: + rv = new Object[size]; + body(data,0,rv); + int body = size-keylimit(); + if(body>0) { + key(data,body,rv); + } + break; + default: + rv = new Object[size]; + key(data,0,rv); + if(size>keylimit()) { + body(data,keylimit(),rv); + } + break; + } + return rv; + } + + public static void writeString(DataOutputStream os, String s) throws IOException { + if(s==null) { + os.writeInt(-1); + } else { + switch(s.length()) { + case 0: + os.writeInt(0); + break; + default: + byte[] bytes = s.getBytes(); + os.writeInt(bytes.length); + os.write(bytes); + } + } + } + + + /** + * We use bytes here to set a Maximum + * + * @param is + * @param MAX + * @return + * @throws IOException + */ + public static String readString(DataInputStream is, byte[] _buff) throws IOException { + int l = is.readInt(); + byte[] buff = _buff; + switch(l) { + case -1: return null; + case 0: return ""; + default: + // Cover case where there is a large string, without always allocating a large buffer. + if(l>buff.length) { + buff = new byte[l]; + } + is.read(buff,0,l); + return new String(buff,0,l); + } + } + + /** + * Write a set with proper sizing + * + * Note: at the moment, this is just String. Probably can develop system where types + * are supported too... but not now. + * + * @param os + * @param set + * @throws IOException + */ + public static void writeStringSet(DataOutputStream os, Collection set) throws IOException { + if(set==null) { + os.writeInt(-1); + } else { + os.writeInt(set.size()); + for(String s : set) { + writeString(os, s); + } + } + + } + + public static Set readStringSet(DataInputStream is, byte[] buff) throws IOException { + int l = is.readInt(); + if(l<0) { + return null; + } + Set set = new HashSet(l); + for(int i=0;i readStringList(DataInputStream is, byte[] buff) throws IOException { + int l = is.readInt(); + if(l<0) { + return null; + } + List list = new ArrayList(l); + for(int i=0;i map) throws IOException { + if(map==null) { + os.writeInt(-1); + } else { + Set> es = map.entrySet(); + os.writeInt(es.size()); + for(Entry e : es) { + writeString(os, e.getKey()); + writeString(os, e.getValue()); + } + } + + } + + public static Map readStringMap(DataInputStream is, byte[] buff) throws IOException { + int l = is.readInt(); + if(l<0) { + return null; + } + Map map = new HashMap(l); + for(int i=0;iversion) { + throw new IOException("Unsupported Data Version: " + v); + } + return v; + } + +} + diff --git a/auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/Streamer.java b/auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/Streamer.java new file mode 100644 index 00000000..c40d74fa --- /dev/null +++ b/auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/Streamer.java @@ -0,0 +1,31 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.dao; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +public interface Streamer { + public abstract void marshal(DATA data, DataOutputStream os) throws IOException; + public abstract void unmarshal(DATA data, DataInputStream is) throws IOException; +} diff --git a/auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/Touchable.java b/auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/Touchable.java new file mode 100644 index 00000000..c00c1048 --- /dev/null +++ b/auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/Touchable.java @@ -0,0 +1,26 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.dao; + +public interface Touchable { + // Or make all DAOs accept list of CIDAOs... +} diff --git a/auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/cached/CachedCertDAO.java b/auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/cached/CachedCertDAO.java new file mode 100644 index 00000000..9526bf28 --- /dev/null +++ b/auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/cached/CachedCertDAO.java @@ -0,0 +1,54 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.dao.cached; + +import java.util.List; + +import org.onap.aaf.auth.dao.CIDAO; +import org.onap.aaf.auth.dao.CachedDAO; +import org.onap.aaf.auth.dao.cass.CertDAO; +import org.onap.aaf.auth.env.AuthzTrans; +import org.onap.aaf.auth.layer.Result; + +public class CachedCertDAO extends CachedDAO { + public CachedCertDAO(CertDAO dao, CIDAO info, long expiresIn) { + super(dao, info, CertDAO.CACHE_SEG, expiresIn); + } + + /** + * Pass through Cert ID Lookup + * + * @param trans + * @param ns + * @return + */ + + public Result> readID(AuthzTrans trans, final String id) { + return dao().readID(trans, id); + } + + public Result> readX500(AuthzTrans trans, final String x500) { + return dao().readX500(trans, x500); + } + + +} diff --git a/auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/cached/CachedCredDAO.java b/auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/cached/CachedCredDAO.java new file mode 100644 index 00000000..76fd5530 --- /dev/null +++ b/auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/cached/CachedCredDAO.java @@ -0,0 +1,66 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.dao.cached; + +import java.util.List; + +import org.onap.aaf.auth.dao.CIDAO; +import org.onap.aaf.auth.dao.CachedDAO; +import org.onap.aaf.auth.dao.cass.CredDAO; +import org.onap.aaf.auth.dao.cass.Status; +import org.onap.aaf.auth.env.AuthzTrans; +import org.onap.aaf.auth.layer.Result; + +public class CachedCredDAO extends CachedDAO { + public CachedCredDAO(CredDAO dao, CIDAO info, long expiresIn) { + super(dao, info, CredDAO.CACHE_SEG, expiresIn); + } + + /** + * Pass through Cred Lookup + * + * Unlike Role and Perm, we don't need or want to cache these elements... Only used for NS Delete. + * + * @param trans + * @param ns + * @return + */ + public Result> readNS(AuthzTrans trans, final String ns) { + + return dao().readNS(trans, ns); + } + + public Result> readID(AuthzTrans trans, final String id) { + DAOGetter getter = new DAOGetter(trans,dao()) { + public Result> call() { + return dao().readID(trans, id); + } + }; + + Result> lurd = get(trans, id, getter); + if(lurd.isOK() && lurd.isEmpty()) { + return Result.err(Status.ERR_UserNotFound,"No User Cred found"); + } + return lurd; + } + +} diff --git a/auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/cached/CachedNSDAO.java b/auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/cached/CachedNSDAO.java new file mode 100644 index 00000000..be860488 --- /dev/null +++ b/auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/cached/CachedNSDAO.java @@ -0,0 +1,33 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.dao.cached; + +import org.onap.aaf.auth.dao.CIDAO; +import org.onap.aaf.auth.dao.CachedDAO; +import org.onap.aaf.auth.dao.cass.NsDAO; +import org.onap.aaf.auth.env.AuthzTrans; + +public class CachedNSDAO extends CachedDAO { + public CachedNSDAO(NsDAO dao, CIDAO info, long expiresIn) { + super(dao, info, NsDAO.CACHE_SEG, expiresIn); + } +} diff --git a/auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/cached/CachedPermDAO.java b/auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/cached/CachedPermDAO.java new file mode 100644 index 00000000..4cb7cf2e --- /dev/null +++ b/auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/cached/CachedPermDAO.java @@ -0,0 +1,124 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.dao.cached; + +import java.util.List; + +import org.onap.aaf.auth.dao.CIDAO; +import org.onap.aaf.auth.dao.CachedDAO; +import org.onap.aaf.auth.dao.cass.PermDAO; +import org.onap.aaf.auth.dao.cass.RoleDAO; +import org.onap.aaf.auth.dao.cass.Status; +import org.onap.aaf.auth.dao.cass.PermDAO.Data; +import org.onap.aaf.auth.env.AuthzTrans; +import org.onap.aaf.auth.layer.Result; + +public class CachedPermDAO extends CachedDAO { + + public CachedPermDAO(PermDAO dao, CIDAO info, long expiresIn) { + super(dao, info, PermDAO.CACHE_SEG, expiresIn); + } + + public Result> readNS(AuthzTrans trans, final String ns) { + DAOGetter getter = new DAOGetter(trans,dao()) { + public Result> call() { + return dao.readNS(trans, ns); + } + }; + + Result> lurd = get(trans, ns, getter); + if(lurd.isOKhasData()) { + return lurd; + } else { + + } +// if(getter.result==null) { +// if(lurd==null) { + return Result.err(Status.ERR_PermissionNotFound,"No Permission found - " + lurd.details); +// } else { +// return Result.ok(lurd); +// } +// } +// return getter.result; + } + + public Result> readChildren(AuthzTrans trans, final String ns, final String type) { + return dao().readChildren(trans,ns,type); + } + + /** + * + * @param trans + * @param ns + * @param type + * @return + */ + public Result> readByType(AuthzTrans trans, final String ns, final String type) { + DAOGetter getter = new DAOGetter(trans,dao()) { + public Result> call() { + return dao.readByType(trans, ns, type); + } + }; + + // Note: Can reuse index1 here, because there is no name collision versus response + Result> lurd = get(trans, ns+'|'+type, getter); + if(lurd.isOK() && lurd.isEmpty()) { + return Result.err(Status.ERR_PermissionNotFound,"No Permission found"); + } + return lurd; + } + + /** + * Add desciption to this permission + * + * @param trans + * @param ns + * @param type + * @param instance + * @param action + * @param description + * @return + */ + public Result addDescription(AuthzTrans trans, String ns, String type, + String instance, String action, String description) { + //TODO Invalidate? + return dao().addDescription(trans, ns, type, instance, action, description); + } + + public Result addRole(AuthzTrans trans, PermDAO.Data perm, RoleDAO.Data role) { + Result rv = dao().addRole(trans,perm,role.encode()); + if(trans.debug().isLoggable()) + trans.debug().log("Adding",role.encode(),"to", perm, "with CachedPermDAO.addRole"); + invalidate(trans,perm); + return rv; + } + + public Result delRole(AuthzTrans trans, Data perm, RoleDAO.Data role) { + Result rv = dao().delRole(trans,perm,role.encode()); + if(trans.debug().isLoggable()) + trans.debug().log("Removing",role.encode(),"from", perm, "with CachedPermDAO.delRole"); + invalidate(trans,perm); + return rv; + } + + +} diff --git a/auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/cached/CachedRoleDAO.java b/auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/cached/CachedRoleDAO.java new file mode 100644 index 00000000..5fac680c --- /dev/null +++ b/auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/cached/CachedRoleDAO.java @@ -0,0 +1,106 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.dao.cached; + +import java.util.List; + +import org.onap.aaf.auth.dao.CIDAO; +import org.onap.aaf.auth.dao.CachedDAO; +import org.onap.aaf.auth.dao.cass.PermDAO; +import org.onap.aaf.auth.dao.cass.RoleDAO; +import org.onap.aaf.auth.dao.cass.Status; +import org.onap.aaf.auth.dao.cass.RoleDAO.Data; +import org.onap.aaf.auth.env.AuthzTrans; +import org.onap.aaf.auth.layer.Result; + +public class CachedRoleDAO extends CachedDAO { + public CachedRoleDAO(RoleDAO dao, CIDAO info, long expiresIn) { + super(dao, info, RoleDAO.CACHE_SEG, expiresIn); + } + + public Result> readNS(AuthzTrans trans, final String ns) { + DAOGetter getter = new DAOGetter(trans,dao()) { + public Result> call() { + return dao.readNS(trans, ns); + } + }; + + Result> lurd = get(trans, ns, getter); + if(lurd.isOK() && lurd.isEmpty()) { + return Result.err(Status.ERR_RoleNotFound,"No Role found"); + } + return lurd; + } + + public Result> readName(AuthzTrans trans, final String name) { + DAOGetter getter = new DAOGetter(trans,dao()) { + public Result> call() { + return dao().readName(trans, name); + } + }; + + Result> lurd = get(trans, name, getter); + if(lurd.isOK() && lurd.isEmpty()) { + return Result.err(Status.ERR_RoleNotFound,"No Role found"); + } + return lurd; + } + + public Result> readChildren(AuthzTrans trans, final String ns, final String name) { + // At this point, I'm thinking it's better not to try to cache "*" results + // Data probably won't be accurate, and adding it makes every update invalidate most of the cache + // Jonathan 2/4/2014 + return dao().readChildren(trans,ns,name); + } + + public Result addPerm(AuthzTrans trans, RoleDAO.Data rd, PermDAO.Data perm) { + Result rv = dao().addPerm(trans,rd,perm); + if(trans.debug().isLoggable()) + trans.debug().log("Adding",perm,"to", rd, "with CachedRoleDAO.addPerm"); + invalidate(trans, rd); + return rv; + } + + public Result delPerm(AuthzTrans trans, RoleDAO.Data rd, PermDAO.Data perm) { + Result rv = dao().delPerm(trans,rd,perm); + if(trans.debug().isLoggable()) + trans.debug().log("Removing",perm,"from", rd, "with CachedRoleDAO.addPerm"); + invalidate(trans, rd); + return rv; + } + + /** + * Add description to this role + * + * @param trans + * @param ns + * @param name + * @param description + * @return + */ + public Result addDescription(AuthzTrans trans, String ns, String name, String description) { + //TODO Invalidate? + return dao().addDescription(trans, ns, name, description); + + } + +} diff --git a/auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/cached/CachedUserRoleDAO.java b/auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/cached/CachedUserRoleDAO.java new file mode 100644 index 00000000..dce2beaa --- /dev/null +++ b/auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/cached/CachedUserRoleDAO.java @@ -0,0 +1,115 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.dao.cached; + +import java.util.ArrayList; +import java.util.List; + +import org.onap.aaf.auth.dao.CIDAO; +import org.onap.aaf.auth.dao.CachedDAO; +import org.onap.aaf.auth.dao.cass.Status; +import org.onap.aaf.auth.dao.cass.UserRoleDAO; +import org.onap.aaf.auth.dao.cass.UserRoleDAO.Data; +import org.onap.aaf.auth.env.AuthzTrans; +import org.onap.aaf.auth.layer.Result; +import org.onap.aaf.misc.env.Slot; + +public class CachedUserRoleDAO extends CachedDAO { + private Slot transURSlot; + + public CachedUserRoleDAO(UserRoleDAO dao, CIDAO info, long expiresIn) { + super(dao, info, UserRoleDAO.CACHE_SEG, expiresIn); + transURSlot = dao.transURSlot; + } + + /** + * Special Case. + * User Roles by User are very likely to be called many times in a Transaction, to validate "May User do..." + * Pull result, and make accessible by the Trans, which is always keyed by User. + * @param trans + * @param user + * @return + */ + public Result> readByUser(AuthzTrans trans, final String user) { + DAOGetter getter = new DAOGetter(trans,dao()) { + public Result> call() { + // If the call is for THIS user, and it exists, get from TRANS, add to TRANS if not. + if(user!=null && user.equals(trans.user())) { + Result> transLD = trans.get(transURSlot,null); + if(transLD==null ) { + transLD = dao.readByUser(trans, user); + } + return transLD; + } else { + return dao.readByUser(trans, user); + } + } + }; + Result> lurd = get(trans, user, getter); + if(lurd.isOK() && lurd.isEmpty()) { + return Result.err(Status.ERR_UserRoleNotFound,"UserRole not found for [%s]",user); + } + return lurd; + } + + + public Result> readByRole(AuthzTrans trans, final String role) { + DAOGetter getter = new DAOGetter(trans,dao()) { + public Result> call() { + return dao.readByRole(trans, role); + } + }; + Result> lurd = get(trans, role, getter); + if(lurd.isOK() && lurd.isEmpty()) { + return Result.err(Status.ERR_UserRoleNotFound,"UserRole not found for [%s]",role); + } + return lurd; + } + + public Result> readUserInRole(final AuthzTrans trans, final String user, final String role) { + DAOGetter getter = new DAOGetter(trans,dao()) { + public Result> call() { + if(user.equals(trans.user())) { + Result> rrbu = readByUser(trans, user); + if(rrbu.isOK()) { + List ld = new ArrayList(1); + for(Data d : rrbu.value) { + if(d.role.equals(role)) { + ld.add(d); + break; + } + } + return Result.ok(ld).emptyList(ld.isEmpty()); + } else { + return rrbu; + } + } + return dao.readByUserRole(trans, user, role); + } + }; + Result> lurd = get(trans, keyFromObjs(user,role), getter); + if(lurd.isOK() && lurd.isEmpty()) { + return Result.err(Status.ERR_UserRoleNotFound,"UserRole not found for role [%s] and user [%s]",role,user); + } + return lurd; + } +} diff --git a/auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/cass/.gitignore b/auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/cass/.gitignore new file mode 100644 index 00000000..e69de29b diff --git a/auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/cass/ApprovalDAO.java b/auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/cass/ApprovalDAO.java new file mode 100644 index 00000000..284d0a84 --- /dev/null +++ b/auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/cass/ApprovalDAO.java @@ -0,0 +1,277 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.dao.cass; + +import java.io.IOException; +import java.util.Date; +import java.util.List; +import java.util.UUID; + +import org.onap.aaf.auth.dao.CassAccess; +import org.onap.aaf.auth.dao.CassDAOImpl; +import org.onap.aaf.auth.dao.Loader; +import org.onap.aaf.auth.env.AuthzTrans; +import org.onap.aaf.auth.layer.Result; +import org.onap.aaf.misc.env.APIException; +import org.onap.aaf.misc.env.Env; +import org.onap.aaf.misc.env.TimeTaken; +import org.onap.aaf.misc.env.util.Chrono; + +import com.datastax.driver.core.Cluster; +import com.datastax.driver.core.ResultSet; +import com.datastax.driver.core.Row; +import com.datastax.driver.core.exceptions.DriverException; + + +public class ApprovalDAO extends CassDAOImpl { + public static final String PENDING = "pending"; + public static final String DENIED = "denied"; + public static final String APPROVED = "approved"; + + private static final String TABLE = "approval"; + private static final String TABLELOG = "approved"; + private HistoryDAO historyDAO; + private PSInfo psByUser, psByApprover, psByTicket, psByStatus; + + + public ApprovalDAO(AuthzTrans trans, Cluster cluster, String keyspace) { + super(trans, ApprovalDAO.class.getSimpleName(),cluster,keyspace,Data.class,TABLE, readConsistency(trans,TABLE), writeConsistency(trans,TABLE)); + historyDAO = new HistoryDAO(trans, this); + init(trans); + } + + + public ApprovalDAO(AuthzTrans trans, HistoryDAO hDAO) { + super(trans, ApprovalDAO.class.getSimpleName(),hDAO,Data.class,TABLE, readConsistency(trans,TABLE), writeConsistency(trans,TABLE)); + historyDAO=hDAO; + init(trans); + } + + private static final int KEYLIMIT = 1; + public static class Data { + public UUID id; + public UUID ticket; + public String user; + public String approver; + public String type; + public String status; + public String memo; + public String operation; + public Date last_notified; + public Date updated; + } + + private static class ApprovalLoader extends Loader { + public static final ApprovalLoader deflt = new ApprovalLoader(KEYLIMIT); + + public ApprovalLoader(int keylimit) { + super(keylimit); + } + + @Override + public Data load(Data data, Row row) { + data.id = row.getUUID(0); + data.ticket = row.getUUID(1); + data.user = row.getString(2); + data.approver = row.getString(3); + data.type = row.getString(4); + data.status = row.getString(5); + data.memo = row.getString(6); + data.operation = row.getString(7); + data.last_notified = row.getTimestamp(8); + // This is used to get "WRITETIME(STATUS)" from Approval, which gives us an "updated" + if(row.getColumnDefinitions().size()>9) { + // Rows reported in MicroSeconds + data.updated = new Date(row.getLong(9)/1000); + } + return data; + } + + @Override + protected void key(Data data, int idx, Object[] obj) { + obj[idx]=data.id; + } + + @Override + protected void body(Data data, int _idx, Object[] obj) { + int idx = _idx; + obj[idx]=data.ticket; + obj[++idx]=data.user; + obj[++idx]=data.approver; + obj[++idx]=data.type; + obj[++idx]=data.status; + obj[++idx]=data.memo; + obj[++idx]=data.operation; + obj[++idx]=data.last_notified; + } + } + + private void init(AuthzTrans trans) { + String[] helpers = setCRUD(trans, TABLE, Data.class, ApprovalLoader.deflt,9); + psByUser = new PSInfo(trans, SELECT_SP + helpers[FIELD_COMMAS] + ", WRITETIME(status) FROM " + TABLE + + " WHERE user = ?", new ApprovalLoader(1) { + @Override + protected void key(Data data, int idx, Object[] obj) { + obj[idx]=data.user; + } + }, readConsistency); + + psByApprover = new PSInfo(trans, SELECT_SP + helpers[FIELD_COMMAS] + ", WRITETIME(status) FROM " + TABLE + + " WHERE approver = ?", new ApprovalLoader(1) { + @Override + protected void key(Data data, int idx, Object[] obj) { + obj[idx]=data.approver; + } + }, readConsistency); + + psByTicket = new PSInfo(trans, SELECT_SP + helpers[FIELD_COMMAS] + ", WRITETIME(status) FROM " + TABLE + + " WHERE ticket = ?", new ApprovalLoader(1) { + @Override + protected void key(Data data, int idx, Object[] obj) { + obj[idx]=data.ticket; + } + }, readConsistency); + + psByStatus = new PSInfo(trans, SELECT_SP + helpers[FIELD_COMMAS] + ", WRITETIME(status) FROM " + TABLE + + " WHERE status = ?", new ApprovalLoader(1) { + @Override + protected void key(Data data, int idx, Object[] obj) { + obj[idx]=data.status; + } + }, readConsistency); + + + } + + /* (non-Javadoc) + * @see org.onap.aaf.auth.dao.CassDAOImpl#create(com.att.inno.env.TransStore, java.lang.Object) + */ + @Override + public Result create(AuthzTrans trans, Data data) { + // If ID is not set (typical), create one. + if(data.id==null) { + data.id = Chrono.dateToUUID(System.currentTimeMillis()); + } + Result rs = createPS.exec(trans, C_TEXT, data); + if(rs.notOK()) { + return Result.err(rs); + } + return Result.ok(data); + } + + + public Result> readByUser(AuthzTrans trans, String user) { + return psByUser.read(trans, R_TEXT, new Object[]{user}); + } + + public Result> readByApprover(AuthzTrans trans, String approver) { + return psByApprover.read(trans, R_TEXT, new Object[]{approver}); + } + + public Result> readByTicket(AuthzTrans trans, UUID ticket) { + return psByTicket.read(trans, R_TEXT, new Object[]{ticket}); + } + + public Result> readByStatus(AuthzTrans trans, String status) { + return psByStatus.read(trans, R_TEXT, new Object[]{status}); + } + + /* (non-Javadoc) + * @see org.onap.aaf.auth.dao.CassDAOImpl#delete(com.att.inno.env.TransStore, java.lang.Object, boolean) + */ + @Override + public Result delete(AuthzTrans trans, Data data, boolean reread) { + if(reread || data.status == null) { // if Memo is empty, likely not full record + Result rd = readPS.exec(trans, R_TEXT, data); + if(rd.notOK()) { + return Result.err(rd); + } + ApprovalLoader.deflt.load(data, rd.value.one()); + } + if("approved".equals(data.status) || "denied".equals(data.status)) { + StringBuilder sb = new StringBuilder("BEGIN BATCH\n"); + sb.append("INSERT INTO "); + sb.append(TABLELOG); + sb.append(" (id,user,approver,type,status,memo,operation) VALUES ("); + sb.append(data.id); + sb.append(",'"); sb.append(data.user); + sb.append("','"); sb.append(data.approver); + sb.append("','"); sb.append(data.type); + sb.append("','"); sb.append(data.status); + sb.append("','"); sb.append(data.memo.replace("'", "''")); + sb.append("','"); sb.append(data.operation); + sb.append("');\n"); + sb.append("DELETE FROM "); + sb.append(TABLE); + sb.append(" WHERE id="); + sb.append(data.id); + sb.append(";\n"); + sb.append("APPLY BATCH;\n"); + TimeTaken tt = trans.start("DELETE APPROVAL",Env.REMOTE); + try { + if(async) { + getSession(trans).executeAsync(sb.toString()); + return Result.ok(); + } else { + getSession(trans).execute(sb.toString()); + return Result.ok(); + } + } catch (DriverException | APIException | IOException e) { + reportPerhapsReset(trans,e); + return Result.err(Result.ERR_Backend, CassAccess.ERR_ACCESS_MSG); + } finally { + tt.done(); + } + } else { + return super.delete(trans, data, false); + } + + } + + + /** + * Log Modification statements to History + * + * @param modified which CRUD action was done + * @param data entity data that needs a log entry + * @param overrideMessage if this is specified, we use it rather than crafting a history message based on data + */ + @Override + protected void wasModified(AuthzTrans trans, CRUD modified, Data data, String ... override) { + boolean memo = override.length>0 && override[0]!=null; + boolean subject = override.length>1 && override[1]!=null; + + HistoryDAO.Data hd = HistoryDAO.newInitedData(); + hd.user = trans.user(); + hd.action = modified.name(); + hd.target = TABLE; + hd.subject = subject?override[1]:data.user + "|" + data.approver; + hd.memo = memo + ? String.format("%s by %s", override[0], hd.user) + : (modified.name() + "d approval for " + data.user); + // Detail? + // Reconstruct? + if(historyDAO.create(trans, hd).status!=Status.OK) { + trans.error().log("Cannot log to History"); + } + } +} diff --git a/auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/cass/ArtiDAO.java b/auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/cass/ArtiDAO.java new file mode 100644 index 00000000..391b55b4 --- /dev/null +++ b/auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/cass/ArtiDAO.java @@ -0,0 +1,303 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.dao.cass; + +import java.io.ByteArrayOutputStream; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.nio.ByteBuffer; +import java.util.Date; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import org.onap.aaf.auth.dao.Bytification; +import org.onap.aaf.auth.dao.CassDAOImpl; +import org.onap.aaf.auth.dao.Loader; +import org.onap.aaf.auth.dao.Streamer; +import org.onap.aaf.auth.env.AuthzTrans; +import org.onap.aaf.auth.layer.Result; +import org.onap.aaf.misc.env.util.Chrono; + +import com.datastax.driver.core.Cluster; +import com.datastax.driver.core.Row; + +/** + * CredDAO manages credentials. + * @author Jonathan + * Date: 7/19/13 + */ +public class ArtiDAO extends CassDAOImpl { + public static final String TABLE = "artifact"; + + private HistoryDAO historyDAO; + private PSInfo psByMechID,psByMachine, psByNs; + + public ArtiDAO(AuthzTrans trans, Cluster cluster, String keyspace) { + super(trans, ArtiDAO.class.getSimpleName(),cluster, keyspace, Data.class,TABLE, readConsistency(trans,TABLE), writeConsistency(trans,TABLE)); + init(trans); + } + + public ArtiDAO(AuthzTrans trans, HistoryDAO hDao, CacheInfoDAO ciDao) { + super(trans, ArtiDAO.class.getSimpleName(),hDao, Data.class,TABLE, readConsistency(trans,TABLE), writeConsistency(trans,TABLE)); + historyDAO = hDao; + init(trans); + } + + public static final int KEYLIMIT = 2; + public static class Data implements Bytification { + public String mechid; + public String machine; + private Set type; + public String sponsor; + public String ca; + public String dir; + public String ns; + public String os_user; + public String notify; + public Date expires; + public int renewDays; + public Set sans; + +// // Getters + public Set type(boolean mutable) { + if (type == null) { + type = new HashSet(); + } else if (mutable && !(type instanceof HashSet)) { + type = new HashSet(type); + } + return type; + } + + public Set sans(boolean mutable) { + if (sans == null) { + sans = new HashSet(); + } else if (mutable && !(sans instanceof HashSet)) { + sans = new HashSet(sans); + } + return sans; + } + + @Override + public ByteBuffer bytify() throws IOException { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + ArtifactLoader.deflt.marshal(this,new DataOutputStream(baos)); + return ByteBuffer.wrap(baos.toByteArray()); + } + + @Override + public void reconstitute(ByteBuffer bb) throws IOException { + ArtifactLoader.deflt.unmarshal(this, toDIS(bb)); + } + + public String toString() { + return mechid + ' ' + machine + ' ' + Chrono.dateTime(expires); + } + } + + private static class ArtifactLoader extends Loader implements Streamer{ + public static final int MAGIC=95829343; + public static final int VERSION=1; + public static final int BUFF_SIZE=48; // Note: + + public static final ArtifactLoader deflt = new ArtifactLoader(KEYLIMIT); + public ArtifactLoader(int keylimit) { + super(keylimit); + } + + @Override + public Data load(Data data, Row row) { + data.mechid = row.getString(0); + data.machine = row.getString(1); + data.type = row.getSet(2, String.class); + data.sponsor = row.getString(3); + data.ca = row.getString(4); + data.dir = row.getString(5); + data.ns = row.getString(6); + data.os_user = row.getString(7); + data.notify = row.getString(8); + data.expires = row.getTimestamp(9); + data.renewDays = row.getInt(10); + data.sans = row.getSet(11, String.class); + return data; + } + + @Override + protected void key(final Data data, final int idx, Object[] obj) { + int i; + obj[i=idx] = data.mechid; + obj[++i] = data.machine; + } + + @Override + protected void body(final Data data, final int idx, Object[] obj) { + int i; + obj[i=idx] = data.type; + obj[++i] = data.sponsor; + obj[++i] = data.ca; + obj[++i] = data.dir; + obj[++i] = data.ns; + obj[++i] = data.os_user; + obj[++i] = data.notify; + obj[++i] = data.expires; + obj[++i] = data.renewDays; + obj[++i] = data.sans; + } + + @Override + public void marshal(Data data, DataOutputStream os) throws IOException { + writeHeader(os,MAGIC,VERSION); + writeString(os, data.mechid); + writeString(os, data.machine); + os.writeInt(data.type.size()); + for(String s : data.type) { + writeString(os, s); + } + writeString(os, data.sponsor); + writeString(os, data.ca); + writeString(os, data.dir); + writeString(os, data.ns); + writeString(os, data.os_user); + writeString(os, data.notify); + os.writeLong(data.expires==null?-1:data.expires.getTime()); + os.writeInt(data.renewDays); + if(data.sans!=null) { + os.writeInt(data.sans.size()); + for(String s : data.sans) { + writeString(os, s); + } + } else { + os.writeInt(0); + } + } + + @Override + public void unmarshal(Data data, DataInputStream is) throws IOException { + /*int version = */readHeader(is,MAGIC,VERSION); + // If Version Changes between Production runs, you'll need to do a switch Statement, and adequately read in fields + byte[] buff = new byte[BUFF_SIZE]; + data.mechid = readString(is,buff); + data.machine = readString(is,buff); + int size = is.readInt(); + data.type = new HashSet(size); + for(int i=0;i(size); + for(int i=0;i> readByMechID(AuthzTrans trans, String mechid) { + return psByMechID.read(trans, R_TEXT, new Object[]{mechid}); + } + + public Result> readByMachine(AuthzTrans trans, String machine) { + return psByMachine.read(trans, R_TEXT, new Object[]{machine}); + } + + public Result> readByNs(AuthzTrans trans, String ns) { + return psByNs.read(trans, R_TEXT, new Object[]{ns}); + } + + /** + * Log Modification statements to History + * + * @param modified which CRUD action was done + * @param data entity data that needs a log entry + * @param overrideMessage if this is specified, we use it rather than crafting a history message based on data + */ + @Override + protected void wasModified(AuthzTrans trans, CRUD modified, Data data, String ... override) { + boolean memo = override.length>0 && override[0]!=null; + boolean subject = override.length>1 && override[1]!=null; + + HistoryDAO.Data hd = HistoryDAO.newInitedData(); + hd.user = trans.user(); + hd.action = modified.name(); + hd.target = TABLE; + hd.subject = subject?override[1]: data.mechid; + hd.memo = memo + ? String.format("%s by %s", override[0], hd.user) + : String.format("%sd %s for %s",modified.name(),data.mechid,data.machine); + // Detail? + if(modified==CRUD.delete) { + try { + hd.reconstruct = data.bytify(); + } catch (IOException e) { + trans.error().log(e,"Could not serialize CredDAO.Data"); + } + } + + if(historyDAO.create(trans, hd).status!=Status.OK) { + trans.error().log("Cannot log to History"); + } + } +} diff --git a/auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/cass/CacheInfoDAO.java b/auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/cass/CacheInfoDAO.java new file mode 100644 index 00000000..e47e9352 --- /dev/null +++ b/auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/cass/CacheInfoDAO.java @@ -0,0 +1,464 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.dao.cass; + +import java.io.IOException; +import java.net.HttpURLConnection; +import java.net.URI; +import java.util.Date; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Map.Entry; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.TimeUnit; + +import org.onap.aaf.auth.dao.AbsCassDAO; +import org.onap.aaf.auth.dao.CIDAO; +import org.onap.aaf.auth.dao.CassAccess; +import org.onap.aaf.auth.dao.CassDAOImpl; +import org.onap.aaf.auth.dao.Loader; +import org.onap.aaf.auth.env.AuthzEnv; +import org.onap.aaf.auth.env.AuthzTrans; +import org.onap.aaf.auth.layer.Result; +import org.onap.aaf.cadi.CadiException; +import org.onap.aaf.cadi.SecuritySetter; +import org.onap.aaf.cadi.client.Future; +import org.onap.aaf.cadi.client.Rcli; +import org.onap.aaf.cadi.client.Retryable; +import org.onap.aaf.cadi.http.HMangr; +import org.onap.aaf.misc.env.APIException; +import org.onap.aaf.misc.env.Env; +import org.onap.aaf.misc.env.TimeTaken; +import org.onap.aaf.misc.env.Trans; + +import com.datastax.driver.core.BoundStatement; +import com.datastax.driver.core.Cluster; +import com.datastax.driver.core.PreparedStatement; +import com.datastax.driver.core.ResultSet; +import com.datastax.driver.core.Row; +import com.datastax.driver.core.exceptions.DriverException; + +public class CacheInfoDAO extends CassDAOImpl implements CIDAO { + + private static final String TABLE = "cache"; + public static final Map info = new ConcurrentHashMap(); + + private static CacheUpdate cacheUpdate; + + // Hold current time stamps from Tables + private final Date startTime; + private PreparedStatement psCheck; + + public CacheInfoDAO(AuthzTrans trans, Cluster cluster, String keyspace) throws APIException, IOException { + super(trans, CacheInfoDAO.class.getSimpleName(),cluster,keyspace,Data.class,TABLE,readConsistency(trans,TABLE), writeConsistency(trans,TABLE)); + startTime = new Date(); + init(trans); + } + + public CacheInfoDAO(AuthzTrans trans, AbsCassDAO aDao) throws APIException, IOException { + super(trans, CacheInfoDAO.class.getSimpleName(),aDao,Data.class,TABLE,readConsistency(trans,TABLE), writeConsistency(trans,TABLE)); + startTime = new Date(); + init(trans); + } + + + ////////////////////////////////////////// + // Data Definition, matches Cassandra DM + ////////////////////////////////////////// + private static final int KEYLIMIT = 2; + /** + * @author Jonathan + */ + public static class Data { + public Data() { + name = null; + touched = null; + } + public Data(String name, int seg) { + this.name = name; + this.seg = seg; + touched = null; + } + + public String name; + public int seg; + public Date touched; + } + + private static class InfoLoader extends Loader { + public static final InfoLoader dflt = new InfoLoader(KEYLIMIT); + + public InfoLoader(int keylimit) { + super(keylimit); + } + + @Override + public Data load(Data data, Row row) { + // Int more efficient + data.name = row.getString(0); + data.seg = row.getInt(1); + data.touched = row.getTimestamp(2); + return data; + } + + @Override + protected void key(Data data, int _idx, Object[] obj) { + int idx = _idx; + + obj[idx]=data.name; + obj[++idx]=data.seg; + } + + @Override + protected void body(Data data, int idx, Object[] obj) { + obj[idx]=data.touched; + } + } + + public static void startUpdate(AuthzEnv env, HMangr hman, SecuritySetter ss, String ip, int port) { + if(cacheUpdate==null) { + Thread t= new Thread(cacheUpdate = new CacheUpdate(env,hman,ss, ip,port),"CacheInfo Update Thread"); + t.setDaemon(true); + t.start(); + } + } + + public static void stopUpdate() { + if(cacheUpdate!=null) { + cacheUpdate.go=false; + } + } + + private final static class CacheUpdate extends Thread { + public static BlockingQueue notifyDQ = new LinkedBlockingQueue(2000); + + private static final String VOID_CT="application/Void+json;q=1.0;charset=utf-8;version=2.0,application/json;q=1.0;version=2.0,*/*;q=1.0"; + private AuthzEnv env; + private HMangr hman; + private SecuritySetter ss; + private final String authority; + public boolean go = true; + + public CacheUpdate(AuthzEnv env, HMangr hman, SecuritySetter ss, String ip, int port) { + this.env = env; + this.hman = hman; + this.ss = ss; + + this.authority = ip+':'+port; + } + + private static class Transfer { + public String table; + public int segs[]; + public Transfer(String table, int[] segs) { + this.table = table; + this.segs = segs; + } + } + private class CacheClear extends Retryable { + public int total=0; + private AuthzTrans trans; + private String type; + private String segs; + + public CacheClear(AuthzTrans trans) { + this.trans = trans; + } + + public void set(Entry es) { + type = es.getKey(); + segs = es.getValue().toString(); + } + + @Override + public Integer code(Rcli client) throws APIException, CadiException { + URI to = client.getURI(); + if(!to.getAuthority().equals(authority)) { + Future f = client.delete("/mgmt/cache/"+type+'/'+segs,VOID_CT); + if(f.get(hman.readTimeout())) { + ++total; + } else { + trans.error().log("Error During AAF Peer Notify",f.code(),f.body()); + } + } + return total; + } + } + + private class IntHolder { + private int[] raw; + HashSet set; + + public IntHolder(int ints[]) { + raw = ints; + set = null; + } + public void add(int[] ints) { + if(set==null) { + set = new HashSet(); + + for(int i=0;i gather = null; + AuthzTrans trans = null; + long start=0; + // Do a block poll first + do { + if(gather==null) { + start = System.nanoTime(); + trans = env.newTransNoAvg(); + cc = new CacheClear(trans); + gather = new HashMap(); + } + IntHolder prev = gather.get(data.table); + if(prev==null) { + gather.put(data.table,new IntHolder(data.segs)); + } else { + prev.add(data.segs); + } + // continue while there is data + } while((data = notifyDQ.poll())!=null); + if(gather!=null) { + for(Entry es : gather.entrySet()) { + cc.set(es); + try { + if(hman.all(ss, cc, false)!=null) { + ++count; + } + } catch (Exception e) { + trans.error().log(e, "Error on Cache Update"); + } + } + if(env.debug().isLoggable()) { + float millis = (System.nanoTime()-start)/1000000f; + StringBuilder sb = new StringBuilder("Direct Cache Refresh: "); + sb.append("Updated "); + sb.append(count); + if(count==1) { + sb.append(" entry for "); + } else { + sb.append(" entries for "); + } + int peers = count<=0?0:cc.total/count; + sb.append(peers); + sb.append(" client"); + if(peers!=1) { + sb.append('s'); + } + sb.append(" in "); + sb.append(millis); + sb.append("ms"); + trans.auditTrail(0, sb, Env.REMOTE); + env.debug().log(sb); + } + } + } catch (InterruptedException e1) { + go = false; + } + } while(go); + } + } + + private void init(AuthzTrans trans) throws APIException, IOException { + + String[] helpers = setCRUD(trans, TABLE, Data.class, InfoLoader.dflt); + psCheck = getSession(trans).prepare(SELECT_SP + helpers[FIELD_COMMAS] + " FROM " + TABLE); + + disable(CRUD.create); + disable(CRUD.delete); + } + + /* (non-Javadoc) + * @see org.onap.aaf.auth.dao.cass.CIDAO#touch(org.onap.aaf.auth.env.test.AuthzTrans, java.lang.String, int) + */ + + @Override + public Result touch(AuthzTrans trans, String name, int ... seg) { + ///////////// + // Direct Service Cache Invalidation + ///////////// + // ConcurrentQueues are open-ended. We don't want any Memory leaks + // Note: we keep a separate counter, because "size()" on a Linked Queue is expensive + if(cacheUpdate!=null) { + try { + if(!CacheUpdate.notifyDQ.offer(new CacheUpdate.Transfer(name, seg),2,TimeUnit.SECONDS)) { + trans.error().log("Cache Notify Queue is not accepting messages, bouncing may be appropriate" ); + } + } catch (InterruptedException e) { + trans.error().log("Cache Notify Queue posting was interrupted" ); + } + } + + ///////////// + // Table Based Cache Invalidation (original) + ///////////// + // Note: Save time with multiple Sequence Touches, but PreparedStmt doesn't support IN + StringBuilder start = new StringBuilder("CacheInfoDAO Touch segments "); + start.append(name); + start.append(": "); + StringBuilder sb = new StringBuilder("BEGIN BATCH\n"); + boolean first = true; + for(int s : seg) { + sb.append(UPDATE_SP); + sb.append(TABLE); + sb.append(" SET touched=dateof(now()) WHERE name = '"); + sb.append(name); + sb.append("' AND seg = "); + sb.append(s); + sb.append(";\n"); + if(first) { + first =false; + } else { + start.append(','); + } + start.append(s); + } + sb.append("APPLY BATCH;"); + TimeTaken tt = trans.start(start.toString(),Env.REMOTE); + try { + getSession(trans).executeAsync(sb.toString()); + } catch (DriverException | APIException | IOException e) { + reportPerhapsReset(trans,e); + return Result.err(Result.ERR_Backend, CassAccess.ERR_ACCESS_MSG); + } finally { + tt.done(); + } + return Result.ok(); + } + + /* (non-Javadoc) + * @see org.onap.aaf.auth.dao.cass.CIDAO#check(org.onap.aaf.auth.env.test.AuthzTrans) + */ + @Override + public Result check(AuthzTrans trans) { + ResultSet rs; + TimeTaken tt = trans.start("Check Table Timestamps",Env.REMOTE); + try { + rs = getSession(trans).execute(new BoundStatement(psCheck)); + } catch (DriverException | APIException | IOException e) { + reportPerhapsReset(trans,e); + return Result.err(Result.ERR_Backend, CassAccess.ERR_ACCESS_MSG); + } finally { + tt.done(); + } + + String lastName = null; + Date[] dates = null; + for(Row row : rs.all()) { + String name = row.getString(0); + int seg = row.getInt(1); + if(!name.equals(lastName)) { + dates = info.get(name); + lastName=name; + } + if(dates==null) { + dates=new Date[seg+1]; + info.put(name,dates); + } else if(dates.length<=seg) { + Date[] temp = new Date[seg+1]; + System.arraycopy(dates, 0, temp, 0, dates.length); + dates = temp; + info.put(name, dates); + } + Date temp = row.getTimestamp(2); + if(dates[seg]==null || dates[seg].before(temp)) { + dates[seg]=temp; + } + } + return Result.ok(); + } + + /* (non-Javadoc) + * @see org.onap.aaf.auth.dao.cass.CIDAO#get(java.lang.String, int) + */ + @Override + public Date get(AuthzTrans trans, String table, int seg) { + Date[] dates = info.get(table); + if(dates==null) { + dates = new Date[seg+1]; + touch(trans,table, seg); + } else if(dates.length<=seg) { + Date[] temp = new Date[seg+1]; + System.arraycopy(dates, 0, temp, 0, dates.length); + dates = temp; + } + Date rv = dates[seg]; + if(rv==null) { + rv=dates[seg]=startTime; + } + return rv; + } + + @Override + protected void wasModified(AuthzTrans trans, CRUD modified, Data data, String ... override) { + // Do nothing + } + +} \ No newline at end of file diff --git a/auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/cass/CacheableData.java b/auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/cass/CacheableData.java new file mode 100644 index 00000000..af4b2302 --- /dev/null +++ b/auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/cass/CacheableData.java @@ -0,0 +1,35 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.dao.cass; + +import org.onap.aaf.auth.dao.Cacheable; +import org.onap.aaf.auth.dao.Cached; +import org.onap.aaf.auth.dao.CachedDAO; + +public abstract class CacheableData implements Cacheable { + // WARNING: DON'T attempt to add any members here, as it will + // be treated by system as fields expected in Tables + protected int seg(Cached cache, Object ... fields) { + return cache==null?0:cache.invalidate(CachedDAO.keyFromObjs(fields)); + } + +} diff --git a/auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/cass/CertDAO.java b/auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/cass/CertDAO.java new file mode 100644 index 00000000..a47b8c9e --- /dev/null +++ b/auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/cass/CertDAO.java @@ -0,0 +1,244 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.dao.cass; + +import java.io.ByteArrayOutputStream; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.math.BigInteger; +import java.nio.ByteBuffer; +import java.util.List; + +import org.onap.aaf.auth.dao.Bytification; +import org.onap.aaf.auth.dao.CIDAO; +import org.onap.aaf.auth.dao.Cached; +import org.onap.aaf.auth.dao.CassDAOImpl; +import org.onap.aaf.auth.dao.Loader; +import org.onap.aaf.auth.dao.Streamer; +import org.onap.aaf.auth.env.AuthzTrans; +import org.onap.aaf.auth.layer.Result; +import org.onap.aaf.misc.env.APIException; + +import com.datastax.driver.core.Cluster; +import com.datastax.driver.core.Row; + +/** + * CredDAO manages credentials. + * @author Jonathan + * Date: 7/19/13 + */ +public class CertDAO extends CassDAOImpl { + public static final String TABLE = "x509"; + public static final int CACHE_SEG = 0x40; // yields segment 0x0-0x3F + + private HistoryDAO historyDAO; + private CIDAO infoDAO; + private PSInfo psX500,psID; + + public CertDAO(AuthzTrans trans, Cluster cluster, String keyspace) throws APIException, IOException { + super(trans, CertDAO.class.getSimpleName(),cluster, keyspace, Data.class,TABLE, readConsistency(trans,TABLE), writeConsistency(trans,TABLE)); + init(trans); + } + + public CertDAO(AuthzTrans trans, HistoryDAO hDao, CacheInfoDAO ciDao) throws APIException, IOException { + super(trans, CertDAO.class.getSimpleName(),hDao, Data.class,TABLE, readConsistency(trans,TABLE), writeConsistency(trans,TABLE)); + historyDAO = hDao; + infoDAO = ciDao; + init(trans); + } + + public static final int KEYLIMIT = 2; + public static class Data extends CacheableData implements Bytification { + + public String ca; + public BigInteger serial; + public String id; + public String x500; + public String x509; + + @Override + public int[] invalidate(Cached cache) { + return new int[] { + seg(cache,ca,serial) + }; + } + + @Override + public ByteBuffer bytify() throws IOException { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + CertLoader.deflt.marshal(this,new DataOutputStream(baos)); + return ByteBuffer.wrap(baos.toByteArray()); + } + + @Override + public void reconstitute(ByteBuffer bb) throws IOException { + CertLoader.deflt.unmarshal(this, toDIS(bb)); + } + } + + private static class CertLoader extends Loader implements Streamer{ + public static final int MAGIC=85102934; + public static final int VERSION=1; + public static final int BUFF_SIZE=48; // Note: + + public static final CertLoader deflt = new CertLoader(KEYLIMIT); + public CertLoader(int keylimit) { + super(keylimit); + } + + @Override + public Data load(Data data, Row row) { + data.ca = row.getString(0); + ByteBuffer bb = row.getBytesUnsafe(1); + byte[] bytes = new byte[bb.remaining()]; + bb.get(bytes); + data.serial = new BigInteger(bytes); + data.id = row.getString(2); + data.x500 = row.getString(3); + data.x509 = row.getString(4); + return data; + } + + @Override + protected void key(Data data, int idx, Object[] obj) { + obj[idx] = data.ca; + obj[++idx] = ByteBuffer.wrap(data.serial.toByteArray()); + } + + @Override + protected void body(Data data, int _idx, Object[] obj) { + int idx = _idx; + + obj[idx] = data.id; + obj[++idx] = data.x500; + obj[++idx] = data.x509; + + + } + + @Override + public void marshal(Data data, DataOutputStream os) throws IOException { + writeHeader(os,MAGIC,VERSION); + writeString(os, data.id); + writeString(os, data.x500); + writeString(os, data.x509); + writeString(os, data.ca); + if(data.serial==null) { + os.writeInt(-1); + } else { + byte[] dsba = data.serial.toByteArray(); + int l = dsba.length; + os.writeInt(l); + os.write(dsba,0,l); + } + } + + @Override + public void unmarshal(Data data, DataInputStream is) throws IOException { + /*int version = */readHeader(is,MAGIC,VERSION); + // If Version Changes between Production runs, you'll need to do a switch Statement, and adequately read in fields + byte[] buff = new byte[BUFF_SIZE]; + data.id = readString(is,buff); + data.x500 = readString(is,buff); + data.x509 = readString(is,buff); + data.ca = readString(is,buff); + int i = is.readInt(); + if(i<0) { + data.serial=null; + } else { + byte[] bytes = new byte[i]; // a bit dangerous, but lessened because of all the previous sized data reads + is.read(bytes); + data.serial = new BigInteger(bytes); + } + } + } + + public Result> read(AuthzTrans trans, Object ... key) { + // Translate BigInteger to Byte array for lookup + return super.read(trans, key[0],ByteBuffer.wrap(((BigInteger)key[1]).toByteArray())); + } + + private void init(AuthzTrans trans) throws APIException, IOException { + // Set up sub-DAOs + if(historyDAO==null) { + historyDAO = new HistoryDAO(trans,this); + } + if(infoDAO==null) { + infoDAO = new CacheInfoDAO(trans,this); + } + + String[] helpers = setCRUD(trans, TABLE, Data.class, CertLoader.deflt); + + psID = new PSInfo(trans, SELECT_SP + helpers[FIELD_COMMAS] + " FROM " + TABLE + + " WHERE id = ?", CertLoader.deflt,readConsistency); + + psX500 = new PSInfo(trans, SELECT_SP + helpers[FIELD_COMMAS] + " FROM " + TABLE + + " WHERE x500 = ?", CertLoader.deflt,readConsistency); + + } + + public Result> readX500(AuthzTrans trans, String x500) { + return psX500.read(trans, R_TEXT, new Object[]{x500}); + } + + public Result> readID(AuthzTrans trans, String id) { + return psID.read(trans, R_TEXT, new Object[]{id}); + } + + /** + * Log Modification statements to History + * + * @param modified which CRUD action was done + * @param data entity data that needs a log entry + * @param overrideMessage if this is specified, we use it rather than crafting a history message based on data + */ + @Override + protected void wasModified(AuthzTrans trans, CRUD modified, Data data, String ... override) { + boolean memo = override.length>0 && override[0]!=null; + boolean subject = override.length>1 && override[1]!=null; + + HistoryDAO.Data hd = HistoryDAO.newInitedData(); + hd.user = trans.user(); + hd.action = modified.name(); + hd.target = TABLE; + hd.subject = subject?override[1]: data.id; + hd.memo = memo + ? String.format("%s by %s", override[0], hd.user) + : (modified.name() + "d certificate info for " + data.id); + // Detail? + if(modified==CRUD.delete) { + try { + hd.reconstruct = data.bytify(); + } catch (IOException e) { + trans.error().log(e,"Could not serialize CertDAO.Data"); + } + } + + if(historyDAO.create(trans, hd).status!=Status.OK) { + trans.error().log("Cannot log to History"); + } + if(infoDAO.touch(trans, TABLE,data.invalidate(cache)).status!=Status.OK) { + trans.error().log("Cannot touch Cert"); + } + } +} diff --git a/auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/cass/CredDAO.java b/auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/cass/CredDAO.java new file mode 100644 index 00000000..46dc12bf --- /dev/null +++ b/auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/cass/CredDAO.java @@ -0,0 +1,258 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.dao.cass; + +import java.io.ByteArrayOutputStream; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.nio.ByteBuffer; +import java.util.Date; +import java.util.List; + +import org.onap.aaf.auth.dao.Bytification; +import org.onap.aaf.auth.dao.CIDAO; +import org.onap.aaf.auth.dao.Cached; +import org.onap.aaf.auth.dao.CassDAOImpl; +import org.onap.aaf.auth.dao.Loader; +import org.onap.aaf.auth.dao.Streamer; +import org.onap.aaf.auth.env.AuthzTrans; +import org.onap.aaf.auth.layer.Result; +import org.onap.aaf.misc.env.APIException; +import org.onap.aaf.misc.env.util.Chrono; + +import com.datastax.driver.core.Cluster; +import com.datastax.driver.core.Row; + +/** + * CredDAO manages credentials. + * @author Jonathan + * Date: 7/19/13 + */ +public class CredDAO extends CassDAOImpl { + public static final String TABLE = "cred"; + public static final int CACHE_SEG = 0x40; // yields segment 0x0-0x3F + public static final int RAW = -1; + public static final int BASIC_AUTH = 1; + public static final int BASIC_AUTH_SHA256 = 2; + public static final int CERT_SHA256_RSA =200; + + private HistoryDAO historyDAO; + private CIDAO infoDAO; + private PSInfo psNS; + private PSInfo psID; + + public CredDAO(AuthzTrans trans, Cluster cluster, String keyspace) throws APIException, IOException { + super(trans, CredDAO.class.getSimpleName(),cluster, keyspace, Data.class,TABLE, readConsistency(trans,TABLE), writeConsistency(trans,TABLE)); + init(trans); + } + + public CredDAO(AuthzTrans trans, HistoryDAO hDao, CacheInfoDAO ciDao) throws APIException, IOException { + super(trans, CredDAO.class.getSimpleName(),hDao, Data.class,TABLE, readConsistency(trans,TABLE), writeConsistency(trans,TABLE)); + historyDAO = hDao; + infoDAO = ciDao; + init(trans); + } + + public static final int KEYLIMIT = 3; + public static class Data extends CacheableData implements Bytification { + + public String id; + public Integer type; + public Date expires; + public Integer other; + public String ns; + public String notes; + public ByteBuffer cred; // this is a blob in cassandra + + + @Override + public int[] invalidate(Cached cache) { + return new int[] { + seg(cache,id) // cache is for all entities + }; + } + + @Override + public ByteBuffer bytify() throws IOException { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + CredLoader.deflt.marshal(this,new DataOutputStream(baos)); + return ByteBuffer.wrap(baos.toByteArray()); + } + + @Override + public void reconstitute(ByteBuffer bb) throws IOException { + CredLoader.deflt.unmarshal(this, toDIS(bb)); + } + + public String toString() { + return id + ' ' + type + ' ' + Chrono.dateTime(expires); + } + } + + private static class CredLoader extends Loader implements Streamer{ + public static final int MAGIC=153323443; + public static final int VERSION=1; + public static final int BUFF_SIZE=48; // Note: + + public static final CredLoader deflt = new CredLoader(KEYLIMIT); + public CredLoader(int keylimit) { + super(keylimit); + } + + @Override + public Data load(Data data, Row row) { + data.id = row.getString(0); + data.type = row.getInt(1); // NOTE: in datastax driver, If the int value is NULL, 0 is returned! + data.expires = row.getTimestamp(2); + data.other = row.getInt(3); + data.ns = row.getString(4); + data.notes = row.getString(5); + data.cred = row.getBytesUnsafe(6); + return data; + } + + @Override + protected void key(Data data, int _idx, Object[] obj) { + int idx = _idx; + + obj[idx] = data.id; + obj[++idx] = data.type; + obj[++idx] = data.expires; + } + + @Override + protected void body(Data data, int idx, Object[] obj) { + int i; + obj[i=idx] = data.other; + obj[++i] = data.ns; + obj[++i] = data.notes; + obj[++i] = data.cred; + } + + @Override + public void marshal(Data data, DataOutputStream os) throws IOException { + writeHeader(os,MAGIC,VERSION); + writeString(os, data.id); + os.writeInt(data.type); + os.writeLong(data.expires==null?-1:data.expires.getTime()); + os.writeInt(data.other==null?0:data.other); + writeString(os, data.ns); + writeString(os, data.notes); + if(data.cred==null) { + os.writeInt(-1); + } else { + int l = data.cred.limit()-data.cred.position(); + os.writeInt(l); + os.write(data.cred.array(),data.cred.position(),l); + } + } + + @Override + public void unmarshal(Data data, DataInputStream is) throws IOException { + /*int version = */readHeader(is,MAGIC,VERSION); + // If Version Changes between Production runs, you'll need to do a switch Statement, and adequately read in fields + byte[] buff = new byte[BUFF_SIZE]; + data.id = readString(is,buff); + data.type = is.readInt(); + + long l = is.readLong(); + data.expires = l<0?null:new Date(l); + data.other = is.readInt(); + data.ns = readString(is,buff); + data.notes = readString(is,buff); + + int i = is.readInt(); + if(i<0) { + data.cred=null; + } else { + byte[] bytes = new byte[i]; // a bit dangerous, but lessened because of all the previous sized data reads + is.read(bytes); + data.cred = ByteBuffer.wrap(bytes); + } + } + } + + private void init(AuthzTrans trans) throws APIException, IOException { + // Set up sub-DAOs + if(historyDAO==null) { + historyDAO = new HistoryDAO(trans,this); + } + if(infoDAO==null) { + infoDAO = new CacheInfoDAO(trans,this); + } + + + String[] helpers = setCRUD(trans, TABLE, Data.class, CredLoader.deflt); + + psNS = new PSInfo(trans, SELECT_SP + helpers[FIELD_COMMAS] + " FROM " + TABLE + + " WHERE ns = ?", CredLoader.deflt,readConsistency); + + psID = new PSInfo(trans, SELECT_SP + helpers[FIELD_COMMAS] + " FROM " + TABLE + + " WHERE id = ?", CredLoader.deflt,readConsistency); + } + + public Result> readNS(AuthzTrans trans, String ns) { + return psNS.read(trans, R_TEXT, new Object[]{ns}); + } + + public Result> readID(AuthzTrans trans, String id) { + return psID.read(trans, R_TEXT, new Object[]{id}); + } + + /** + * Log Modification statements to History + * + * @param modified which CRUD action was done + * @param data entity data that needs a log entry + * @param overrideMessage if this is specified, we use it rather than crafting a history message based on data + */ + @Override + protected void wasModified(AuthzTrans trans, CRUD modified, Data data, String ... override) { + boolean memo = override.length>0 && override[0]!=null; + boolean subject = override.length>1 && override[1]!=null; + + HistoryDAO.Data hd = HistoryDAO.newInitedData(); + hd.user = trans.user(); + hd.action = modified.name(); + hd.target = TABLE; + hd.subject = subject?override[1]: data.id; + hd.memo = memo + ? String.format("%s by %s", override[0], hd.user) + : (modified.name() + "d credential for " + data.id); + // Detail? + if(modified==CRUD.delete) { + try { + hd.reconstruct = data.bytify(); + } catch (IOException e) { + trans.error().log(e,"Could not serialize CredDAO.Data"); + } + } + + if(historyDAO.create(trans, hd).status!=Status.OK) { + trans.error().log("Cannot log to History"); + } + if(infoDAO.touch(trans, TABLE,data.invalidate(cache)).status!=Status.OK) { + trans.error().log("Cannot touch Cred"); + } + } +} diff --git a/auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/cass/DelegateDAO.java b/auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/cass/DelegateDAO.java new file mode 100644 index 00000000..78a98e1d --- /dev/null +++ b/auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/cass/DelegateDAO.java @@ -0,0 +1,138 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.dao.cass; + +import java.io.ByteArrayOutputStream; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.nio.ByteBuffer; +import java.util.Date; +import java.util.List; + +import org.onap.aaf.auth.dao.AbsCassDAO; +import org.onap.aaf.auth.dao.Bytification; +import org.onap.aaf.auth.dao.CassDAOImpl; +import org.onap.aaf.auth.dao.Loader; +import org.onap.aaf.auth.dao.Streamer; +import org.onap.aaf.auth.env.AuthzTrans; +import org.onap.aaf.auth.layer.Result; + +import com.datastax.driver.core.Cluster; +import com.datastax.driver.core.Row; + +public class DelegateDAO extends CassDAOImpl { + + public static final String TABLE = "delegate"; + private PSInfo psByDelegate; + + public DelegateDAO(AuthzTrans trans, Cluster cluster, String keyspace) { + super(trans, DelegateDAO.class.getSimpleName(),cluster,keyspace,Data.class,TABLE, readConsistency(trans,TABLE), writeConsistency(trans,TABLE)); + init(trans); + } + + public DelegateDAO(AuthzTrans trans, AbsCassDAO aDao) { + super(trans, DelegateDAO.class.getSimpleName(),aDao,Data.class,TABLE, readConsistency(trans,TABLE), writeConsistency(trans,TABLE)); + init(trans); + } + + private static final int KEYLIMIT = 1; + public static class Data implements Bytification { + public String user; + public String delegate; + public Date expires; + + @Override + public ByteBuffer bytify() throws IOException { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + DelegateLoader.dflt.marshal(this,new DataOutputStream(baos)); + return ByteBuffer.wrap(baos.toByteArray()); + } + + @Override + public void reconstitute(ByteBuffer bb) throws IOException { + DelegateLoader.dflt.unmarshal(this, toDIS(bb)); + } + } + + private static class DelegateLoader extends Loader implements Streamer{ + public static final int MAGIC=0xD823ACF2; + public static final int VERSION=1; + public static final int BUFF_SIZE=48; + + public static final DelegateLoader dflt = new DelegateLoader(KEYLIMIT); + + public DelegateLoader(int keylimit) { + super(keylimit); + } + + @Override + public Data load(Data data, Row row) { + data.user = row.getString(0); + data.delegate = row.getString(1); + data.expires = row.getTimestamp(2); + return data; + } + + @Override + protected void key(Data data, int idx, Object[] obj) { + obj[idx]=data.user; + } + + @Override + protected void body(Data data, int _idx, Object[] obj) { + int idx = _idx; + + obj[idx]=data.delegate; + obj[++idx]=data.expires; + } + + @Override + public void marshal(Data data, DataOutputStream os) throws IOException { + writeHeader(os,MAGIC,VERSION); + writeString(os, data.user); + writeString(os, data.delegate); + os.writeLong(data.expires.getTime()); + } + + @Override + public void unmarshal(Data data, DataInputStream is) throws IOException { + /*int version = */readHeader(is,MAGIC,VERSION); + // If Version Changes between Production runs, you'll need to do a switch Statement, and adequately read in fields + byte[] buff = new byte[BUFF_SIZE]; + data.user = readString(is, buff); + data.delegate = readString(is,buff); + data.expires = new Date(is.readLong()); + } + } + + private void init(AuthzTrans trans) { + String[] helpers = setCRUD(trans, TABLE, Data.class, DelegateLoader.dflt); + psByDelegate = new PSInfo(trans, SELECT_SP + helpers[FIELD_COMMAS] + " FROM " + TABLE + + " WHERE delegate = ?", new DelegateLoader(1),readConsistency); + + } + + public Result> readByDelegate(AuthzTrans trans, String delegate) { + return psByDelegate.read(trans, R_TEXT, new Object[]{delegate}); + } +} diff --git a/auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/cass/FutureDAO.java b/auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/cass/FutureDAO.java new file mode 100644 index 00000000..0263e009 --- /dev/null +++ b/auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/cass/FutureDAO.java @@ -0,0 +1,183 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.dao.cass; + +import java.nio.ByteBuffer; +import java.util.Date; +import java.util.List; +import java.util.UUID; + +import org.onap.aaf.auth.dao.CassDAOImpl; +import org.onap.aaf.auth.dao.DAOException; +import org.onap.aaf.auth.dao.Loader; +import org.onap.aaf.auth.env.AuthzTrans; +import org.onap.aaf.auth.layer.Result; + +import com.datastax.driver.core.Cluster; +import com.datastax.driver.core.ResultSet; +import com.datastax.driver.core.Row; + +/** + * FutureDAO stores Construction information to create + * elements at another time. + * + * @author Jonathan + * 8/20/2013 + */ +public class FutureDAO extends CassDAOImpl { + private static final String TABLE = "future"; + private final HistoryDAO historyDAO; +// private static String createString; + private PSInfo psByStartAndTarget; + + public FutureDAO(AuthzTrans trans, Cluster cluster, String keyspace) { + super(trans, FutureDAO.class.getSimpleName(),cluster, keyspace, Data.class,TABLE, readConsistency(trans,TABLE), writeConsistency(trans,TABLE)); + historyDAO = new HistoryDAO(trans, this); + init(trans); + } + + public FutureDAO(AuthzTrans trans, HistoryDAO hDAO) { + super(trans, FutureDAO.class.getSimpleName(),hDAO, Data.class,TABLE, readConsistency(trans,TABLE), writeConsistency(trans,TABLE)); + historyDAO=hDAO; + init(trans); + } + + public static final int KEYLIMIT = 1; + public static class Data { + public UUID id; + public String target; + public String memo; + public Date start; + public Date expires; + public ByteBuffer construct; // this is a blob in cassandra + } + + private static class FLoader extends Loader { + public FLoader() { + super(KEYLIMIT); + } + + public FLoader(int keylimit) { + super(keylimit); + } + + @Override + public Data load(Data data, Row row) { + data.id = row.getUUID(0); + data.target = row.getString(1); + data.memo = row.getString(2); + data.start = row.getTimestamp(3); + data.expires = row.getTimestamp(4); + data.construct = row.getBytes(5); + return data; + } + + @Override + protected void key(Data data, int idx, Object[] obj) { + obj[idx] = data.id; + } + + @Override + protected void body(Data data, int _idx, Object[] obj) { + int idx = _idx; + + obj[idx] = data.target; + obj[++idx] = data.memo; + obj[++idx] = data.start; + obj[++idx] = data.expires; + obj[++idx] = data.construct; + } + } + + private void init(AuthzTrans trans) { + // Set up sub-DAOs + String[] helpers = setCRUD(trans, TABLE, Data.class, new FLoader(KEYLIMIT)); + + // Uh, oh. Can't use "now()" in Prepared Statements (at least at this level) +// createString = "INSERT INTO " + TABLE + " ("+helpers[FIELD_COMMAS] +") VALUES (now(),"; +// +// // Need a specialty Creator to handle the "now()" +// replace(CRUD.Create, new PSInfo(trans, "INSERT INTO future (" + helpers[FIELD_COMMAS] + +// ") VALUES(now(),?,?,?,?,?)",new FLoader(0))); + + // Other SELECT style statements... match with a local Method + psByStartAndTarget = new PSInfo(trans, SELECT_SP + helpers[FIELD_COMMAS] + + " FROM future WHERE start <= ? and target = ? ALLOW FILTERING", new FLoader(2) { + @Override + protected void key(Data data, int _idx, Object[] obj) { + int idx = _idx; + + obj[idx]=data.start; + obj[++idx]=data.target; + } + },readConsistency); + + + } + + public Result> readByStartAndTarget(AuthzTrans trans, Date start, String target) throws DAOException { + return psByStartAndTarget.read(trans, R_TEXT, new Object[]{start, target}); + } + + /** + * Override create to add secondary ID to Subject in History, and create Data.ID, if it is null + */ + public Result create(AuthzTrans trans, FutureDAO.Data data, String id) { + // If ID is not set (typical), create one. + if(data.id==null) { + StringBuilder sb = new StringBuilder(trans.user()); + sb.append(data.target); + sb.append(System.currentTimeMillis()); + data.id = UUID.nameUUIDFromBytes(sb.toString().getBytes()); + } + Result rs = createPS.exec(trans, C_TEXT, data); + if(rs.notOK()) { + return Result.err(rs); + } + wasModified(trans, CRUD.create, data, null, id); + return Result.ok(data); + } + + /** + * Log Modification statements to History + * + * @param modified which CRUD action was done + * @param data entity data that needs a log entry + * @param overrideMessage if this is specified, we use it rather than crafting a history message based on data + */ + @Override + protected void wasModified(AuthzTrans trans, CRUD modified, Data data, String ... override) { + boolean memo = override.length>0 && override[0]!=null; + boolean subject = override.length>1 && override[1]!=null; + HistoryDAO.Data hd = HistoryDAO.newInitedData(); + hd.user = trans.user(); + hd.action = modified.name(); + hd.target = TABLE; + hd.subject = subject?override[1]:""; + hd.memo = memo?String.format("%s by %s", override[0], hd.user):data.memo; + + if(historyDAO.create(trans, hd).status!=Status.OK) { + trans.error().log("Cannot log to History"); + } + } + +} diff --git a/auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/cass/HistoryDAO.java b/auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/cass/HistoryDAO.java new file mode 100644 index 00000000..8e4ada10 --- /dev/null +++ b/auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/cass/HistoryDAO.java @@ -0,0 +1,238 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.dao.cass; + +import java.nio.ByteBuffer; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.List; +import java.util.UUID; + +import org.onap.aaf.auth.dao.AbsCassDAO; +import org.onap.aaf.auth.dao.CassDAOImpl; +import org.onap.aaf.auth.dao.Loader; +import org.onap.aaf.auth.env.AuthzTrans; +import org.onap.aaf.auth.layer.Result; + +import com.datastax.driver.core.Cluster; +import com.datastax.driver.core.ConsistencyLevel; +import com.datastax.driver.core.ResultSet; +import com.datastax.driver.core.Row; + +/** + * History + * + * Originally written PE3617 + * @author Jonathan + * + * History is a special case, because we don't want Updates or Deletes... Too likely to mess up history. + * + * Jonathan 9-9-2013 - Found a problem with using "Prepare". You cannot prepare anything with a "now()" in it, as + * it is evaluated once during the prepare, and kept. That renders any use of "now()" pointless. Therefore + * the Create function needs to be run fresh everytime. + * + * Fixed in Cassandra 1.2.6 https://issues.apache.org/jira/browse/CASSANDRA-5616 + * + */ +public class HistoryDAO extends CassDAOImpl { + private static final String TABLE = "history"; + + public static final SimpleDateFormat monthFormat = new SimpleDateFormat("yyyyMM"); +// private static final SimpleDateFormat dayTimeFormat = new SimpleDateFormat("ddHHmmss"); + + private String[] helpers; + + private HistLoader defLoader; + + private AbsCassDAO.PSInfo readByUser, readBySubject, readByYRMN; + + public HistoryDAO(AuthzTrans trans, Cluster cluster, String keyspace) { + super(trans, HistoryDAO.class.getSimpleName(),cluster,keyspace,Data.class,TABLE,ConsistencyLevel.LOCAL_ONE,ConsistencyLevel.ANY); + init(trans); + } + + public HistoryDAO(AuthzTrans trans, AbsCassDAO aDao) { + super(trans, HistoryDAO.class.getSimpleName(),aDao,Data.class,TABLE,ConsistencyLevel.LOCAL_ONE,ConsistencyLevel.ANY); + init(trans); + } + + + private static final int KEYLIMIT = 1; + public static class Data { + public UUID id; + public int yr_mon; + public String user; + public String action; + public String target; + public String subject; + public String memo; +// Map detail = null; +// public Map detail() { +// if(detail == null) { +// detail = new HashMap(); +// } +// return detail; +// } + public ByteBuffer reconstruct; + } + + private static class HistLoader extends Loader { + public HistLoader(int keylimit) { + super(keylimit); + } + + @Override + public Data load(Data data, Row row) { + data.id = row.getUUID(0); + data.yr_mon = row.getInt(1); + data.user = row.getString(2); + data.action = row.getString(3); + data.target = row.getString(4); + data.subject = row.getString(5); + data.memo = row.getString(6); +// data.detail = row.getMap(6, String.class, String.class); + data.reconstruct = row.getBytes(7); + return data; + } + + @Override + protected void key(Data data, int idx, Object[] obj) { + obj[idx]=data.id; + } + + @Override + protected void body(Data data, int _idx, Object[] obj) { + int idx = _idx; + obj[idx]=data.yr_mon; + obj[++idx]=data.user; + obj[++idx]=data.action; + obj[++idx]=data.target; + obj[++idx]=data.subject; + obj[++idx]=data.memo; +// obj[++idx]=data.detail; + obj[++idx]=data.reconstruct; + } + }; + + private void init(AuthzTrans trans) { + // Loader must match fields order + defLoader = new HistLoader(KEYLIMIT); + helpers = setCRUD(trans, TABLE, Data.class, defLoader); + + // Need a specialty Creator to handle the "now()" + // 9/9/2013 - Jonathan - Just great... now() is evaluated once on Client side, invalidating usage (what point is a now() from a long time in the past? + // Unless this is fixed, we're putting in non-prepared statement + // Solved in Cassandra. Make sure you are running 1.2.6 Cassandra or later. https://issues.apache.org/jira/browse/CASSANDRA-5616 + replace(CRUD.create, new PSInfo(trans, "INSERT INTO history (" + helpers[FIELD_COMMAS] + + ") VALUES(now(),?,?,?,?,?,?,?)", + new HistLoader(0) { + @Override + protected void key(Data data, int idx, Object[] obj) { + } + },writeConsistency) + ); +// disable(CRUD.Create); + + replace(CRUD.read, new PSInfo(trans, SELECT_SP + helpers[FIELD_COMMAS] + + " FROM history WHERE id = ?", defLoader,readConsistency) +// new HistLoader(2) { +// @Override +// protected void key(Data data, int idx, Object[] obj) { +// obj[idx]=data.yr_mon; +// obj[++idx]=data.id; +// } +// }) + ); + disable(CRUD.update); + disable(CRUD.delete); + + readByUser = new PSInfo(trans, SELECT_SP + helpers[FIELD_COMMAS] + + " FROM history WHERE user = ?", defLoader,readConsistency); + readBySubject = new PSInfo(trans, SELECT_SP + helpers[FIELD_COMMAS] + + " FROM history WHERE subject = ? and target = ? ALLOW FILTERING", defLoader,readConsistency); + readByYRMN = new PSInfo(trans, SELECT_SP + helpers[FIELD_COMMAS] + + " FROM history WHERE yr_mon = ?", defLoader,readConsistency); + async(true); //TODO dropping messages with Async + } + + public static Data newInitedData() { + Data data = new Data(); + Date now = new Date(); + data.yr_mon = Integer.parseInt(monthFormat.format(now)); + // data.day_time = Integer.parseInt(dayTimeFormat.format(now)); + return data; + } + + public Result> readByYYYYMM(AuthzTrans trans, int yyyymm) { + Result rs = readByYRMN.exec(trans, "yr_mon", yyyymm); + if(rs.notOK()) { + return Result.err(rs); + } + return extract(defLoader,rs.value,null,dflt); + } + + /** + * Gets the history for a user in the specified year and month + * year - the year in yyyy format + * month - the month in a year ...values 1 - 12 + **/ + public Result> readByUser(AuthzTrans trans, String user, int ... yyyymm) { + if(yyyymm.length==0) { + return Result.err(Status.ERR_BadData, "No or invalid yyyymm specified"); + } + Result rs = readByUser.exec(trans, "user", user); + if(rs.notOK()) { + return Result.err(rs); + } + return extract(defLoader,rs.value,null,yyyymm.length>0?new YYYYMM(yyyymm):dflt); + } + + public Result> readBySubject(AuthzTrans trans, String subject, String target, int ... yyyymm) { + if(yyyymm.length==0) { + return Result.err(Status.ERR_BadData, "No or invalid yyyymm specified"); + } + Result rs = readBySubject.exec(trans, "subject", subject, target); + if(rs.notOK()) { + return Result.err(rs); + } + return extract(defLoader,rs.value,null,yyyymm.length>0?new YYYYMM(yyyymm):dflt); + } + + private class YYYYMM implements Accept { + private int[] yyyymm; + public YYYYMM(int yyyymm[]) { + this.yyyymm = yyyymm; + } + @Override + public boolean ok(Data data) { + int dym = data.yr_mon; + for(int ym:yyyymm) { + if(dym==ym) { + return true; + } + } + return false; + } + + }; + +} diff --git a/auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/cass/LocateDAO.java b/auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/cass/LocateDAO.java new file mode 100644 index 00000000..bdf2748c --- /dev/null +++ b/auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/cass/LocateDAO.java @@ -0,0 +1,231 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.dao.cass; + +import java.io.ByteArrayOutputStream; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.nio.ByteBuffer; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.UUID; + +import org.onap.aaf.auth.dao.AbsCassDAO; +import org.onap.aaf.auth.dao.Bytification; +import org.onap.aaf.auth.dao.CassDAOImpl; +import org.onap.aaf.auth.dao.Loader; +import org.onap.aaf.auth.dao.Streamer; +import org.onap.aaf.auth.env.AuthzTrans; +import org.onap.aaf.auth.layer.Result; +import org.onap.aaf.misc.env.APIException; + +import com.datastax.driver.core.Cluster; +import com.datastax.driver.core.Row; + +/** + * LocateDAO manages credentials. + * @author Jonathan + * Date: 10/11/17 + */ +public class LocateDAO extends CassDAOImpl { + public static final String TABLE = "locate"; + private AbsCassDAO.PSInfo psName; + + public LocateDAO(AuthzTrans trans, Cluster cluster, String keyspace) throws APIException, IOException { + super(trans, LocateDAO.class.getSimpleName(),cluster, keyspace, Data.class,TABLE, readConsistency(trans,TABLE), writeConsistency(trans,TABLE)); + init(trans); + } + + public LocateDAO(AuthzTrans trans, AbsCassDAO adao) throws APIException, IOException { + super(trans, LocateDAO.class.getSimpleName(), adao, Data.class,TABLE, readConsistency(trans,TABLE), writeConsistency(trans,TABLE)); + init(trans); + } + + public static final int KEYLIMIT = 3; + public static class Data implements Bytification { + + public String name; + public String hostname; + public int port; + public int major; + public int minor; + public int patch; + public int pkg; + public float latitude; + public float longitude; + public String protocol; + private Set subprotocol; + public UUID port_key; // Note: Keep Port_key LAST at all times, because we shorten the UPDATE to leave Port_key Alone during reregistration. + + // Getters + public Set subprotocol(boolean mutable) { + if (subprotocol == null) { + subprotocol = new HashSet(); + } else if (mutable && !(subprotocol instanceof HashSet)) { + subprotocol = new HashSet(subprotocol); + } + return subprotocol; + } + + @Override + public ByteBuffer bytify() throws IOException { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + LocateLoader.deflt.marshal(this,new DataOutputStream(baos)); + return ByteBuffer.wrap(baos.toByteArray()); + } + + @Override + public void reconstitute(ByteBuffer bb) throws IOException { + LocateLoader.deflt.unmarshal(this, toDIS(bb)); + } + } + + private static class LocateLoader extends Loader implements Streamer{ + public static final int MAGIC=85102934; + public static final int VERSION=1; + public static final int BUFF_SIZE=48; // Note: + + public static final LocateLoader deflt = new LocateLoader(KEYLIMIT); + public LocateLoader(int keylimit) { + super(keylimit); + } + + @Override + public Data load(Data data, Row row) { + data.name = row.getString(0); + data.hostname = row.getString(1); + data.port = row.getInt(2); + data.major = row.getInt(3); + data.minor = row.getInt(4); + data.patch = row.getInt(5); + data.pkg = row.getInt(6); + data.latitude = row.getFloat(7); + data.longitude = row.getFloat(8); + data.protocol = row.getString(9); + data.subprotocol = row.getSet(10,String.class); + data.port_key = row.getUUID(11); + return data; + } + + @Override + protected void key(Data data, int idx, Object[] obj) { + obj[idx] = data.name; + obj[++idx] = data.hostname; + obj[++idx] = data.port; + } + + @Override + protected void body(final Data data, final int _idx, final Object[] obj) { + int idx = _idx; + obj[idx] = data.major; + obj[++idx] = data.minor; + obj[++idx] = data.patch; + obj[++idx] = data.pkg; + obj[++idx] = data.latitude; + obj[++idx] = data.longitude; + obj[++idx] = data.protocol; + obj[++idx] = data.subprotocol; + obj[++idx] = data.port_key; + } + + @Override + public void marshal(Data data, DataOutputStream os) throws IOException { + writeHeader(os,MAGIC,VERSION); + writeString(os, data.name); + writeString(os, data.hostname); + os.writeInt(data.port); + os.writeInt(data.major); + os.writeInt(data.minor); + os.writeInt(data.patch); + os.writeInt(data.pkg); + os.writeFloat(data.latitude); + os.writeFloat(data.longitude); + writeString(os, data.protocol); + if(data.subprotocol==null) { + os.writeInt(0); + } else { + os.writeInt(data.subprotocol.size()); + for(String s: data.subprotocol) { + writeString(os,s); + } + } + + writeString(os,data.port_key==null?"":data.port_key.toString()); + } + + @Override + public void unmarshal(Data data, DataInputStream is) throws IOException { + /*int version = */readHeader(is,MAGIC,VERSION); + // If Version Changes between Production runs, you'll need to do a switch Statement, and adequately read in fields + byte[] buff = new byte[BUFF_SIZE]; + data.name = readString(is,buff); + data.hostname = readString(is,buff); + data.port = is.readInt(); + data.major = is.readInt(); + data.minor = is.readInt(); + data.patch = is.readInt(); + data.pkg = is.readInt(); + data.latitude = is.readFloat(); + data.longitude = is.readFloat(); + data.protocol = readString(is,buff); + + int size = is.readInt(); + data.subprotocol = new HashSet(size); + for(int i=0;i0) { + data.port_key=UUID.fromString(port_key); + } else { + data.port_key = null; + } + } + } + + public Result> readByName(AuthzTrans trans, String service) { + return psName.read(trans, "Read By Name", new Object[] {service}); + } + + private void init(AuthzTrans trans) throws APIException, IOException { + // Set up sub-DAOs + String[] helpers = setCRUD(trans, TABLE, Data.class, LocateLoader.deflt); +// int lastComma = helpers[ASSIGNMENT_COMMAS].lastIndexOf(','); +// replace(CRUD.update,new PSInfo(trans,"UPDATE LOCATE SET " + helpers[ASSIGNMENT_COMMAS].substring(0, lastComma) + +// " WHERE name=? AND hostname=? AND port=?;", new LocateLoader(3),writeConsistency)); + psName = new PSInfo(trans, SELECT_SP + helpers[FIELD_COMMAS] + " FROM " + TABLE + + " WHERE name = ?", new LocateLoader(1),readConsistency); + } + + /** + * Log Modification statements to History + * + * @param modified which CRUD action was done + * @param data entity data that needs a log entry + * @param overrideMessage if this is specified, we use it rather than crafting a history message based on data + */ + @Override + protected void wasModified(AuthzTrans trans, CRUD modified, Data data, String ... override) { + } +} diff --git a/auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/cass/Namespace.java b/auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/cass/Namespace.java new file mode 100644 index 00000000..4b1ff149 --- /dev/null +++ b/auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/cass/Namespace.java @@ -0,0 +1,150 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.dao.cass; + +import java.io.ByteArrayOutputStream; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.List; +import java.util.Map.Entry; + +import org.onap.aaf.auth.dao.Bytification; +import org.onap.aaf.auth.dao.CassDAOImpl; +import org.onap.aaf.auth.dao.Loader; +import org.onap.aaf.auth.rserv.Pair; + + +public class Namespace implements Bytification { + public static final int MAGIC=250935515; + public static final int VERSION=1; + public static final int BUFF_SIZE=48; + + public String name; + public List owner; + public List admin; + public List> attrib; + public String description; + public Integer type; + public String parent; + public Namespace() {} + + public Namespace(NsDAO.Data ndd) { + name = ndd.name; + description = ndd.description; + type = ndd.type; + parent = ndd.parent; + if(ndd.attrib!=null && !ndd.attrib.isEmpty()) { + attrib = new ArrayList>(); + for( Entry entry : ndd.attrib.entrySet()) { + attrib.add(new Pair(entry.getKey(),entry.getValue())); + } + } + } + + public Namespace(NsDAO.Data ndd,List owner, List admin) { + name = ndd.name; + this.owner = owner; + this.admin = admin; + description = ndd.description; + type = ndd.type; + parent = ndd.parent; + if(ndd.attrib!=null && !ndd.attrib.isEmpty()) { + attrib = new ArrayList>(); + for( Entry entry : ndd.attrib.entrySet()) { + attrib.add(new Pair(entry.getKey(),entry.getValue())); + } + } + } + + public NsDAO.Data data() { + NsDAO.Data ndd = new NsDAO.Data(); + ndd.name = name; + ndd.description = description; + ndd.parent = parent; + ndd.type = type; + return ndd; + } + + @Override + public ByteBuffer bytify() throws IOException { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + DataOutputStream os = new DataOutputStream(baos); + + Loader.writeHeader(os,MAGIC,VERSION); + Loader.writeString(os, name); + os.writeInt(type); + Loader.writeStringSet(os,admin); + Loader.writeStringSet(os,owner); + Loader.writeString(os,description); + Loader.writeString(os,parent); + + return ByteBuffer.wrap(baos.toByteArray()); + } + + @Override + public void reconstitute(ByteBuffer bb) throws IOException { + DataInputStream is = CassDAOImpl.toDIS(bb); + /*int version = */Loader.readHeader(is,MAGIC,VERSION); + // If Version Changes between Production runs, you'll need to do a switch Statement, and adequately read in fields + + byte[] buff = new byte[BUFF_SIZE]; + name = Loader.readString(is, buff); + type = is.readInt(); + admin = Loader.readStringList(is,buff); + owner = Loader.readStringList(is,buff); + description = Loader.readString(is,buff); + parent = Loader.readString(is,buff); + + } + + /* (non-Javadoc) + * @see java.lang.Object#hashCode() + */ + @Override + public int hashCode() { + return name.hashCode(); + } + + + /* (non-Javadoc) + * @see java.lang.Object#toString() + */ + @Override + public String toString() { + return name.toString(); + } + + /* (non-Javadoc) + * @see java.lang.Object#equals(java.lang.Object) + */ + @Override + public boolean equals(Object arg0) { + if(arg0==null || !(arg0 instanceof Namespace)) { + return false; + } + return name.equals(((Namespace)arg0).name); + } + +} diff --git a/auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/cass/NsDAO.java b/auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/cass/NsDAO.java new file mode 100644 index 00000000..567246d8 --- /dev/null +++ b/auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/cass/NsDAO.java @@ -0,0 +1,560 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.dao.cass; + +import java.io.ByteArrayOutputStream; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.nio.ByteBuffer; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; + +import org.onap.aaf.auth.dao.Bytification; +import org.onap.aaf.auth.dao.Cached; +import org.onap.aaf.auth.dao.CassAccess; +import org.onap.aaf.auth.dao.CassDAOImpl; +import org.onap.aaf.auth.dao.Loader; +import org.onap.aaf.auth.dao.Streamer; +import org.onap.aaf.auth.env.AuthzTrans; +import org.onap.aaf.auth.layer.Result; +import org.onap.aaf.misc.env.APIException; +import org.onap.aaf.misc.env.Env; +import org.onap.aaf.misc.env.TimeTaken; + +import java.util.Set; + +import com.datastax.driver.core.Cluster; +import com.datastax.driver.core.ResultSet; +import com.datastax.driver.core.Row; +import com.datastax.driver.core.exceptions.DriverException; + +/** + * NsDAO + * + * Data Access Object for Namespace Data + * + * @author Jonathan + * + */ +public class NsDAO extends CassDAOImpl { + public static final String TABLE = "ns"; + public static final String TABLE_ATTRIB = "ns_attrib"; + public static final int CACHE_SEG = 0x40; // yields segment 0x0-0x3F + public static final int ROOT = 1; + public static final int COMPANY=2; + public static final int APP = 3; + + private static final String BEGIN_BATCH = "BEGIN BATCH\n"; + private static final String APPLY_BATCH = "\nAPPLY BATCH;\n"; + private static final String SQSCCR = "';\n"; + private static final String SQCSQ = "','"; + + private HistoryDAO historyDAO; + private CacheInfoDAO infoDAO; + private PSInfo psNS; + + public NsDAO(AuthzTrans trans, Cluster cluster, String keyspace) throws APIException, IOException { + super(trans, NsDAO.class.getSimpleName(),cluster,keyspace,Data.class,TABLE, readConsistency(trans,TABLE), writeConsistency(trans,TABLE)); + init(trans); + } + + public NsDAO(AuthzTrans trans, HistoryDAO hDAO, CacheInfoDAO iDAO) throws APIException, IOException { + super(trans, NsDAO.class.getSimpleName(),hDAO,Data.class,TABLE, readConsistency(trans,TABLE), writeConsistency(trans,TABLE)); + historyDAO=hDAO; + infoDAO = iDAO; + init(trans); + } + + + ////////////////////////////////////////// + // Data Definition, matches Cassandra DM + ////////////////////////////////////////// + private static final int KEYLIMIT = 1; + /** + * Data class that matches the Cassandra Table "role" + * + * @author Jonathan + */ + public static class Data extends CacheableData implements Bytification { + public String name; + public int type; + public String description; + public String parent; + public Map attrib; + +// //////////////////////////////////////// +// // Getters + public Map attrib(boolean mutable) { + if (attrib == null) { + attrib = new HashMap(); + } else if (mutable && !(attrib instanceof HashMap)) { + attrib = new HashMap(attrib); + } + return attrib; + } + + @Override + public int[] invalidate(Cached cache) { + return new int[] { + seg(cache,name) + }; + } + + public NsSplit split(String name) { + return new NsSplit(this,name); + } + + @Override + public ByteBuffer bytify() throws IOException { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + NSLoader.deflt.marshal(this,new DataOutputStream(baos)); + return ByteBuffer.wrap(baos.toByteArray()); + } + + @Override + public void reconstitute(ByteBuffer bb) throws IOException { + NSLoader.deflt.unmarshal(this,toDIS(bb)); + } + + @Override + public String toString() { + return name; + } + + } + + private void init(AuthzTrans trans) throws APIException, IOException { + // Set up sub-DAOs + if(historyDAO==null) { + historyDAO = new HistoryDAO(trans, this); + } + if(infoDAO==null) { + infoDAO = new CacheInfoDAO(trans,this); + } + + String[] helpers = setCRUD(trans, TABLE, Data.class, NSLoader.deflt,4/*need to skip attrib */); + + psNS = new PSInfo(trans, SELECT_SP + helpers[FIELD_COMMAS] + " FROM " + TABLE + + " WHERE parent = ?", new NSLoader(1),readConsistency); + + } + + private static final class NSLoader extends Loader implements Streamer { + public static final int MAGIC=250935515; + public static final int VERSION=1; + public static final int BUFF_SIZE=48; + + public static final NSLoader deflt = new NSLoader(KEYLIMIT); + + public NSLoader(int keylimit) { + super(keylimit); + } + + @Override + public Data load(Data data, Row row) { + // Int more efficient + data.name = row.getString(0); + data.type = row.getInt(1); + data.description = row.getString(2); + data.parent = row.getString(3); + return data; + } + + @Override + protected void key(Data data, int idx, Object[] obj) { + obj[idx]=data.name; + } + + @Override + protected void body(Data data, int _idx, Object[] obj) { + int idx = _idx; + + obj[idx]=data.type; + obj[++idx]=data.description; + obj[++idx]=data.parent; + } + + @Override + public void marshal(Data data, DataOutputStream os) throws IOException { + writeHeader(os,MAGIC,VERSION); + writeString(os, data.name); + os.writeInt(data.type); + writeString(os,data.description); + writeString(os,data.parent); + if(data.attrib==null) { + os.writeInt(-1); + } else { + os.writeInt(data.attrib.size()); + for(Entry es : data.attrib(false).entrySet()) { + writeString(os,es.getKey()); + writeString(os,es.getValue()); + } + } + } + + @Override + public void unmarshal(Data data, DataInputStream is) throws IOException { + /*int version = */readHeader(is,MAGIC,VERSION); + // If Version Changes between Production runs, you'll need to do a switch Statement, and adequately read in fields + + byte[] buff = new byte[BUFF_SIZE]; + data.name = readString(is, buff); + data.type = is.readInt(); + data.description = readString(is,buff); + data.parent = readString(is,buff); + int count = is.readInt(); + if(count>0) { + Map da = data.attrib(true); + for(int i=0;i create(AuthzTrans trans, Data data) { + String ns = data.name; + // Ensure Parent is set + if(data.parent==null) { + return Result.err(Result.ERR_BadData, "Need parent for %s", ns); + } + + // insert Attributes + StringBuilder stmt = new StringBuilder(); + stmt.append(BEGIN_BATCH); + attribInsertStmts(stmt, data); + stmt.append(APPLY_BATCH); + try { + getSession(trans).execute(stmt.toString()); +//// TEST CODE for Exception +// boolean force = true; +// if(force) { +// throw new com.datastax.driver.core.exceptions.NoHostAvailableException(new HashMap()); +//// throw new com.datastax.driver.core.exceptions.AuthenticationException(new InetSocketAddress(9999),"Sample Message"); +// } +////END TEST CODE + + } catch (DriverException | APIException | IOException e) { + reportPerhapsReset(trans,e); + trans.info().log(stmt); + return Result.err(Result.ERR_Backend, "Backend Access"); + } + return super.create(trans, data); + } + + @Override + public Result update(AuthzTrans trans, Data data) { + String ns = data.name; + // Ensure Parent is set + if(data.parent==null) { + return Result.err(Result.ERR_BadData, "Need parent for %s", ns); + } + + StringBuilder stmt = new StringBuilder(); + stmt.append(BEGIN_BATCH); + try { + Map localAttr = data.attrib; + Result> rremoteAttr = readAttribByNS(trans,ns); + if(rremoteAttr.notOK()) { + return Result.err(rremoteAttr); + } + // update Attributes + String str; + for(Entry es : localAttr.entrySet()) { + str = rremoteAttr.value.get(es.getKey()); + if(str==null || !str.equals(es.getValue())) { + attribUpdateStmt(stmt, ns, es.getKey(),es.getValue()); + } + } + + // No point in deleting... insert overwrites... +// for(Entry es : remoteAttr.entrySet()) { +// str = localAttr.get(es.getKey()); +// if(str==null || !str.equals(es.getValue())) { +// attribDeleteStmt(stmt, ns, es.getKey()); +// } +// } + if(stmt.length()>BEGIN_BATCH.length()) { + stmt.append(APPLY_BATCH); + getSession(trans).execute(stmt.toString()); + } + } catch (DriverException | APIException | IOException e) { + reportPerhapsReset(trans,e); + trans.info().log(stmt); + return Result.err(Result.ERR_Backend, CassAccess.ERR_ACCESS_MSG); + } + + return super.update(trans,data); + } + + /* (non-Javadoc) + * @see org.onap.aaf.auth.dao.CassDAOImpl#read(com.att.inno.env.TransStore, java.lang.Object) + */ + @Override + public Result> read(AuthzTrans trans, Data data) { + Result> rld = super.read(trans, data); + + if(rld.isOKhasData()) { + for(Data d : rld.value) { + // Note: Map is null at this point, save time/mem by assignment + Result> rabn = readAttribByNS(trans,d.name); + if(rabn.isOK()) { + d.attrib = rabn.value; + } else { + return Result.err(rabn); + } + } + } + return rld; + } + + /* (non-Javadoc) + * @see org.onap.aaf.auth.dao.CassDAOImpl#read(com.att.inno.env.TransStore, java.lang.Object[]) + */ + @Override + public Result> read(AuthzTrans trans, Object... key) { + Result> rld = super.read(trans, key); + + if(rld.isOKhasData()) { + for(Data d : rld.value) { + // Note: Map is null at this point, save time/mem by assignment + Result> rabn = readAttribByNS(trans,d.name); + if(rabn.isOK()) { + d.attrib = rabn.value; + } else { + return Result.err(rabn); + } + } + } + return rld; + } + + @Override + public Result delete(AuthzTrans trans, Data data, boolean reread) { + TimeTaken tt = trans.start("Delete NS Attributes " + data.name, Env.REMOTE); + try { + StringBuilder stmt = new StringBuilder(); + attribDeleteAllStmt(stmt, data); + try { + getSession(trans).execute(stmt.toString()); + } catch (DriverException | APIException | IOException e) { + reportPerhapsReset(trans,e); + trans.info().log(stmt); + return Result.err(Result.ERR_Backend, CassAccess.ERR_ACCESS_MSG); + } + } finally { + tt.done(); + } + return super.delete(trans, data, reread); + + } + + public Result> readAttribByNS(AuthzTrans trans, String ns) { + Map map = new HashMap(); + TimeTaken tt = trans.start("readAttribByNS " + ns, Env.REMOTE); + try { + ResultSet rs = getSession(trans).execute("SELECT key,value FROM " + + TABLE_ATTRIB + + " WHERE ns='" + + ns + + "';"); + + for(Iterator iter = rs.iterator();iter.hasNext(); ) { + Row r = iter.next(); + map.put(r.getString(0), r.getString(1)); + } + } catch (DriverException | APIException | IOException e) { + reportPerhapsReset(trans,e); + return Result.err(Result.ERR_Backend, CassAccess.ERR_ACCESS_MSG); + } finally { + tt.done(); + } + return Result.ok(map); + } + + public Result> readNsByAttrib(AuthzTrans trans, String key) { + Set set = new HashSet(); + TimeTaken tt = trans.start("readNsBykey " + key, Env.REMOTE); + try { + ResultSet rs = getSession(trans).execute("SELECT ns FROM " + + TABLE_ATTRIB + + " WHERE key='" + + key + + "';"); + + for(Iterator iter = rs.iterator();iter.hasNext(); ) { + Row r = iter.next(); + set.add(r.getString(0)); + } + } catch (DriverException | APIException | IOException e) { + reportPerhapsReset(trans,e); + return Result.err(Result.ERR_Backend, CassAccess.ERR_ACCESS_MSG); + } finally { + tt.done(); + } + return Result.ok(set); + } + + public Result attribAdd(AuthzTrans trans, String ns, String key, String value) { + try { + getSession(trans).execute(attribInsertStmt(new StringBuilder(),ns,key,value).toString()); + return Result.ok(); + } catch (DriverException | APIException | IOException e) { + reportPerhapsReset(trans,e); + return Result.err(Result.ERR_Backend, CassAccess.ERR_ACCESS_MSG); + } + } + + private StringBuilder attribInsertStmt(StringBuilder sb, String ns, String key, String value) { + sb.append("INSERT INTO "); + sb.append(TABLE_ATTRIB); + sb.append(" (ns,key,value) VALUES ('"); + sb.append(ns); + sb.append(SQCSQ); + sb.append(key); + sb.append(SQCSQ); + sb.append(value); + sb.append("');"); + return sb; + } + + private StringBuilder attribUpdateStmt(StringBuilder sb, String ns, String key, String value) { + sb.append("UPDATE "); + sb.append(TABLE_ATTRIB); + sb.append(" set value='"); + sb.append(value); + sb.append("' where ns='"); + sb.append(ns); + sb.append("' AND key='"); + sb.append(key); + sb.append("';"); + return sb; + } + + + public Result attribRemove(AuthzTrans trans, String ns, String key) { + try { + getSession(trans).execute(attribDeleteStmt(new StringBuilder(),ns,key).toString()); + return Result.ok(); + } catch (DriverException | APIException | IOException e) { + reportPerhapsReset(trans,e); + return Result.err(Result.ERR_Backend, CassAccess.ERR_ACCESS_MSG); + } + } + + private StringBuilder attribDeleteStmt(StringBuilder stmt, String ns, String key) { + stmt.append("DELETE FROM "); + stmt.append(TABLE_ATTRIB); + stmt.append(" WHERE ns='"); + stmt.append(ns); + stmt.append("' AND key='"); + stmt.append(key); + stmt.append("';"); + return stmt; + } + + private void attribDeleteAllStmt(StringBuilder stmt, Data data) { + stmt.append(" DELETE FROM "); + stmt.append(TABLE_ATTRIB); + stmt.append(" WHERE ns='"); + stmt.append(data.name); + stmt.append(SQSCCR); + } + + private void attribInsertStmts(StringBuilder stmt, Data data) { + // INSERT new Attrib + for(Entry es : data.attrib(false).entrySet() ) { + stmt.append(" "); + attribInsertStmt(stmt,data.name,es.getKey(),es.getValue()); + } + } + + /** + * Add description to Namespace + * @param trans + * @param ns + * @param description + * @return + */ + public Result addDescription(AuthzTrans trans, String ns, String description) { + try { + getSession(trans).execute(UPDATE_SP + TABLE + " SET description = '" + + description.replace("'", "''") + "' WHERE name = '" + ns + "';"); + } catch (DriverException | APIException | IOException e) { + reportPerhapsReset(trans,e); + return Result.err(Result.ERR_Backend, CassAccess.ERR_ACCESS_MSG); + } + + Data data = new Data(); + data.name=ns; + wasModified(trans, CRUD.update, data, "Added description " + description + " to namespace " + ns, null ); + return Result.ok(); + } + + public Result> getChildren(AuthzTrans trans, String parent) { + return psNS.read(trans, R_TEXT, new Object[]{parent}); + } + + + /** + * Log Modification statements to History + * + * @param modified which CRUD action was done + * @param data entity data that needs a log entry + * @param overrideMessage if this is specified, we use it rather than crafting a history message based on data + */ + @Override + protected void wasModified(AuthzTrans trans, CRUD modified, Data data, String ... override) { + boolean memo = override.length>0 && override[0]!=null; + boolean subject = override.length>1 && override[1]!=null; + + //TODO Must log history + HistoryDAO.Data hd = HistoryDAO.newInitedData(); + hd.user = trans.user(); + hd.action = modified.name(); + hd.target = TABLE; + hd.subject = subject ? override[1] : data.name; + hd.memo = memo ? override[0] : (data.name + " was " + modified.name() + 'd' ); + if(modified==CRUD.delete) { + try { + hd.reconstruct = data.bytify(); + } catch (IOException e) { + trans.error().log(e,"Could not serialize NsDAO.Data"); + } + } + + if(historyDAO.create(trans, hd).status!=Status.OK) { + trans.error().log("Cannot log to History"); + } + if(infoDAO.touch(trans, TABLE,data.invalidate(cache)).notOK()) { + trans.error().log("Cannot touch CacheInfo"); + } + } + +} \ No newline at end of file diff --git a/auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/cass/NsSplit.java b/auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/cass/NsSplit.java new file mode 100644 index 00000000..2694c6c8 --- /dev/null +++ b/auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/cass/NsSplit.java @@ -0,0 +1,61 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.dao.cass; + +public class NsSplit { + public final String ns; + public final String name; + public final NsDAO.Data nsd; + + public NsSplit(NsDAO.Data nsd, String child) { + this.nsd = nsd; + if(child.startsWith(nsd.name)) { + ns = nsd.name; + int dot = ns.length(); + if(dot=0) { + nsd.parent = ns.substring(0, dot); + } else { + nsd.parent = "."; + } + } + + public boolean isOK() { + return ns!=null && name !=null; + } +} \ No newline at end of file diff --git a/auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/cass/NsType.java b/auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/cass/NsType.java new file mode 100644 index 00000000..18d5eeec --- /dev/null +++ b/auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/cass/NsType.java @@ -0,0 +1,74 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.dao.cass; + +/** + * Defines the Type Codes in the NS Table. + * @author Jonathan + * + */ +public enum NsType { + UNKNOWN (-1), + DOT (0), + ROOT (1), + COMPANY (2), + APP (3), + STACKED_APP (10), + STACK (11); + + public final int type; + private NsType(int t) { + type = t; + } + /** + * This is not the Ordinal, but the Type that is stored in NS Tables + * + * @param t + * @return + */ + public static NsType fromType(int t) { + for(NsType nst : values()) { + if(t==nst.type) { + return nst; + } + } + return UNKNOWN; + } + + /** + * Use this one rather than "valueOf" to avoid Exception + * @param s + * @return + */ + public static NsType fromString(String s) { + if(s!=null) { + for(NsType nst : values()) { + if(nst.name().equals(s)) { + return nst; + } + } + } + return UNKNOWN; + } + + +} diff --git a/auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/cass/OAuthTokenDAO.java b/auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/cass/OAuthTokenDAO.java new file mode 100644 index 00000000..e1375b8a --- /dev/null +++ b/auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/cass/OAuthTokenDAO.java @@ -0,0 +1,213 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.dao.cass; + +import java.io.ByteArrayOutputStream; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.nio.ByteBuffer; +import java.util.Date; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import org.onap.aaf.auth.dao.AbsCassDAO; +import org.onap.aaf.auth.dao.Bytification; +import org.onap.aaf.auth.dao.CassDAOImpl; +import org.onap.aaf.auth.dao.Loader; +import org.onap.aaf.auth.dao.Streamer; +import org.onap.aaf.auth.env.AuthzTrans; +import org.onap.aaf.auth.layer.Result; +import org.onap.aaf.misc.env.util.Chrono; + +import com.datastax.driver.core.Cluster; +import com.datastax.driver.core.Row; + +/** + * CredDAO manages credentials. + * @author Jonathan + * Date: 7/19/13 + */ +public class OAuthTokenDAO extends CassDAOImpl { + public static final String TABLE = "oauth_token"; + private AbsCassDAO.PSInfo psByUser; + + public OAuthTokenDAO(AuthzTrans trans, Cluster cluster, String keyspace) { + super(trans, OAuthTokenDAO.class.getSimpleName(),cluster, keyspace, Data.class,TABLE, readConsistency(trans,TABLE), writeConsistency(trans,TABLE)); + init(trans); + } + + public OAuthTokenDAO(AuthzTrans trans, AbsCassDAO aDao) { + super(trans, OAuthTokenDAO.class.getSimpleName(),aDao, Data.class, TABLE, readConsistency(trans,TABLE), writeConsistency(trans,TABLE)); + init(trans); + } + + + public static final int KEYLIMIT = 1; + public static class Data implements Bytification { + public String id; + public String client_id; + public String user; + public boolean active; + public int type; + public String refresh; + public Date expires; + public long exp_sec; + public String content; + public Set scopes; + public String state; + public String req_ip; // requesting + + public Set scopes(boolean mutable) { + if (scopes == null) { + scopes = new HashSet(); + } else if (mutable && !(scopes instanceof HashSet)) { + scopes = new HashSet(scopes); + } + return scopes; + } + + @Override + public ByteBuffer bytify() throws IOException { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + OAuthLoader.deflt.marshal(this,new DataOutputStream(baos)); + return ByteBuffer.wrap(baos.toByteArray()); + } + + @Override + public void reconstitute(ByteBuffer bb) throws IOException { + OAuthLoader.deflt.unmarshal(this, toDIS(bb)); + } + + public String toString() { + return user.toString() + ' ' + id.toString() + ' ' + Chrono.dateTime(expires) + (active?"":"in") + "active"; + } + } + + private static class OAuthLoader extends Loader implements Streamer{ + public static final int MAGIC=235677843; + public static final int VERSION=1; + public static final int BUFF_SIZE=96; // Note: only used when + + public static final OAuthLoader deflt = new OAuthLoader(KEYLIMIT); + public OAuthLoader(int keylimit) { + super(keylimit); + } + + @Override + public Data load(Data data, Row row) { + data.id = row.getString(0); + data.client_id = row.getString(1); + data.user = row.getString(2); + data.active = row.getBool(3); + data.type = row.getInt(4); + data.refresh = row.getString(5); + data.expires = row.getTimestamp(6); + data.exp_sec = row.getLong(7); + data.content = row.getString(8); + data.scopes = row.getSet(9,String.class); + data.state = row.getString(10); + data.req_ip = row.getString(11); + return data; + } + + @Override + protected void key(final Data data, final int idx, Object[] obj) { + obj[idx] = data.id; + } + + @Override + protected void body(final Data data, final int idx, Object[] obj) { + int i; + obj[i=idx] = data.client_id; + obj[++i] = data.user; + obj[++i] = data.active; + obj[++i] = data.type; + obj[++i] = data.refresh; + obj[++i] = data.expires; + obj[++i] = data.exp_sec; + obj[++i] = data.content; + obj[++i] = data.scopes; + obj[++i] = data.state; + obj[++i] = data.req_ip; + } + + @Override + public void marshal(Data data, DataOutputStream os) throws IOException { + writeHeader(os,MAGIC,VERSION); + writeString(os, data.id); + writeString(os, data.client_id); + writeString(os, data.user); + os.writeBoolean(data.active); + os.writeInt(data.type); + writeString(os, data.refresh); + os.writeLong(data.expires==null?-1:data.expires.getTime()); + os.writeLong(data.exp_sec); + writeString(os, data.content); + writeStringSet(os,data.scopes); + writeString(os, data.state); + writeString(os, data.req_ip); + } + + + @Override + public void unmarshal(Data data, DataInputStream is) throws IOException { + /*int version = */readHeader(is,MAGIC,VERSION); + // If Version Changes between Production runs, you'll need to do a switch Statement, and adequately read in fields + byte[] buff = new byte[BUFF_SIZE]; // used only if fits + data.id = readString(is,buff); + data.client_id = readString(is,buff); + data.user = readString(is,buff); + data.active = is.readBoolean(); + data.type = is.readInt(); + data.refresh = readString(is,buff); + long l = is.readLong(); + data.expires = l<0?null:new Date(l); + data.exp_sec = is.readLong(); + data.content = readString(is,buff); // note, large strings still ok with small buffer + data.scopes = readStringSet(is,buff); + data.state = readString(is,buff); + data.req_ip = readString(is,buff); + } + } + + private void init(AuthzTrans trans) { + String[] helpers = setCRUD(trans, TABLE, Data.class, OAuthLoader.deflt); + psByUser = new PSInfo(trans, "SELECT " + helpers[0] + " from " + TABLE + " WHERE user=?",OAuthLoader.deflt,readConsistency); + } + + /** + * Log Modification statements to History + * + * @param modified which CRUD action was done + * @param data entity data that needs a log entry + * @param overrideMessage if this is specified, we use it rather than crafting a history message based on data + */ + @Override + protected void wasModified(AuthzTrans trans, CRUD modified, Data data, String ... override) { + } + + public Result> readByUser(AuthzTrans trans, String user) { + return psByUser.read(trans, "Read By User", new Object[]{user}); + } +} diff --git a/auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/cass/PermDAO.java b/auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/cass/PermDAO.java new file mode 100644 index 00000000..860b7ea5 --- /dev/null +++ b/auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/cass/PermDAO.java @@ -0,0 +1,501 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.dao.cass; + +import java.io.ByteArrayOutputStream; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.nio.ByteBuffer; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import org.onap.aaf.auth.dao.Bytification; +import org.onap.aaf.auth.dao.Cached; +import org.onap.aaf.auth.dao.CassAccess; +import org.onap.aaf.auth.dao.CassDAOImpl; +import org.onap.aaf.auth.dao.DAOException; +import org.onap.aaf.auth.dao.Loader; +import org.onap.aaf.auth.dao.Streamer; +import org.onap.aaf.auth.dao.hl.Question; +import org.onap.aaf.auth.env.AuthzTrans; +import org.onap.aaf.auth.layer.Result; +import org.onap.aaf.misc.env.APIException; +import org.onap.aaf.misc.env.util.Split; + +import com.datastax.driver.core.Cluster; +import com.datastax.driver.core.Row; +import com.datastax.driver.core.exceptions.DriverException; + +public class PermDAO extends CassDAOImpl { + + public static final String TABLE = "perm"; + + public static final int CACHE_SEG = 0x40; // yields segment 0x0-0x3F + private static final String STAR = "*"; + + private final HistoryDAO historyDAO; + private final CacheInfoDAO infoDAO; + + private PSInfo psNS, psChildren, psByType; + + public PermDAO(AuthzTrans trans, Cluster cluster, String keyspace) throws APIException, IOException { + super(trans, PermDAO.class.getSimpleName(),cluster,keyspace,Data.class,TABLE, readConsistency(trans,TABLE), writeConsistency(trans,TABLE)); + init(trans); + historyDAO = new HistoryDAO(trans, this); + infoDAO = new CacheInfoDAO(trans,this); + } + + public PermDAO(AuthzTrans trans, HistoryDAO hDAO, CacheInfoDAO ciDAO) { + super(trans, PermDAO.class.getSimpleName(),hDAO,Data.class,TABLE, readConsistency(trans,TABLE), writeConsistency(trans,TABLE)); + historyDAO = hDAO; + infoDAO=ciDAO; + init(trans); + } + + + private static final int KEYLIMIT = 4; + public static class Data extends CacheableData implements Bytification { + public String ns; + public String type; + public String instance; + public String action; + public Set roles; + public String description; + + public Data() {} + + public Data(NsSplit nss, String instance, String action) { + ns = nss.ns; + type = nss.name; + this.instance = instance; + this.action = action; + } + + public String fullType() { + return ns + '.' + type; + } + + public String fullPerm() { + return ns + '.' + type + '|' + instance + '|' + action; + } + + public String encode() { + return ns + '|' + type + '|' + instance + '|' + action; + } + + /** + * Decode Perm String, including breaking into appropriate Namespace + * + * @param trans + * @param q + * @param p + * @return + */ + public static Result decode(AuthzTrans trans, Question q, String p) { + String[] ss = Split.splitTrim('|', p,4); + if(ss[2]==null) { + return Result.err(Status.ERR_BadData,"Perm Encodings must be separated by '|'"); + } + Data data = new Data(); + if(ss[3]==null) { // older 3 part encoding must be evaluated for NS + Result nss = q.deriveNsSplit(trans, ss[0]); + if(nss.notOK()) { + return Result.err(nss); + } + data.ns=nss.value.ns; + data.type=nss.value.name; + data.instance=ss[1]; + data.action=ss[2]; + } else { // new 4 part encoding + data.ns=ss[0]; + data.type=ss[1]; + data.instance=ss[2]; + data.action=ss[3]; + } + return Result.ok(data); + } + + /** + * Decode Perm String, including breaking into appropriate Namespace + * + * @param trans + * @param q + * @param p + * @return + */ + public static Result decodeToArray(AuthzTrans trans, Question q, String p) { + String[] ss = Split.splitTrim('|', p,4); + if(ss[2]==null) { + return Result.err(Status.ERR_BadData,"Perm Encodings must be separated by '|'"); + } + + if(ss[3]==null) { // older 3 part encoding must be evaluated for NS + ss[3] = ss[2]; + ss[2] = ss[1]; + Result nss = q.deriveNsSplit(trans, ss[0]); + if(nss.notOK()) { + return Result.err(nss); + } + ss[1] = nss.value.name; + ss[0] = nss.value.ns; + } + return Result.ok(ss); + } + + public static Data create(NsDAO.Data ns, String name) { + NsSplit nss = new NsSplit(ns,name); + Data rv = new Data(); + rv.ns = nss.ns; + String[] s = nss.name.split("\\|"); + switch(s.length) { + case 3: + rv.type=s[0]; + rv.instance=s[1]; + rv.action=s[2]; + break; + case 2: + rv.type=s[0]; + rv.instance=s[1]; + rv.action=STAR; + break; + default: + rv.type=s[0]; + rv.instance = STAR; + rv.action = STAR; + } + return rv; + } + + public static Data create(AuthzTrans trans, Question q, String name) { + String[] s = name.split("\\|"); + Result rdns = q.deriveNsSplit(trans, s[0]); + Data rv = new PermDAO.Data(); + if(rdns.isOKhasData()) { + switch(s.length) { + case 3: + rv.type=s[1]; + rv.instance=s[2]; + rv.action=s[3]; + break; + case 2: + rv.type=s[1]; + rv.instance=s[2]; + rv.action=STAR; + break; + default: + rv.type=s[1]; + rv.instance = STAR; + rv.action = STAR; + } + } + return rv; + } + + //////////////////////////////////////// + // Getters + public Set roles(boolean mutable) { + if (roles == null) { + roles = new HashSet(); + } else if (mutable && !(roles instanceof HashSet)) { + roles = new HashSet(roles); + } + return roles; + } + + @Override + public int[] invalidate(Cached cache) { + return new int[] { + seg(cache,ns), + seg(cache,ns,type), + seg(cache,ns,type,STAR), + seg(cache,ns,type,instance,action) + }; + } + + @Override + public ByteBuffer bytify() throws IOException { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + PermLoader.deflt.marshal(this, new DataOutputStream(baos)); + return ByteBuffer.wrap(baos.toByteArray()); + } + + @Override + public void reconstitute(ByteBuffer bb) throws IOException { + PermLoader.deflt.unmarshal(this, toDIS(bb)); + } + + @Override + public String toString() { + return encode(); + } + } + + private static class PermLoader extends Loader implements Streamer { + public static final int MAGIC=283939453; + public static final int VERSION=1; + public static final int BUFF_SIZE=96; + + public static final PermLoader deflt = new PermLoader(KEYLIMIT); + + public PermLoader(int keylimit) { + super(keylimit); + } + + @Override + public Data load(Data data, Row row) { + // Int more efficient Match "fields" string + data.ns = row.getString(0); + data.type = row.getString(1); + data.instance = row.getString(2); + data.action = row.getString(3); + data.roles = row.getSet(4,String.class); + data.description = row.getString(5); + return data; + } + + @Override + protected void key(Data data, int _idx, Object[] obj) { + int idx = _idx; + obj[idx]=data.ns; + obj[++idx]=data.type; + obj[++idx]=data.instance; + obj[++idx]=data.action; + } + + @Override + protected void body(Data data, int _idx, Object[] obj) { + int idx = _idx; + obj[idx]=data.roles; + obj[++idx]=data.description; + } + + @Override + public void marshal(Data data, DataOutputStream os) throws IOException { + writeHeader(os,MAGIC,VERSION); + writeString(os, data.ns); + writeString(os, data.type); + writeString(os, data.instance); + writeString(os, data.action); + writeStringSet(os, data.roles); + writeString(os, data.description); + } + + @Override + public void unmarshal(Data data, DataInputStream is) throws IOException { + /*int version = */readHeader(is,MAGIC,VERSION); + // If Version Changes between Production runs, you'll need to do a switch Statement, and adequately read in fields + byte[] buff = new byte[BUFF_SIZE]; + data.ns = readString(is, buff); + data.type = readString(is,buff); + data.instance = readString(is,buff); + data.action = readString(is,buff); + data.roles = readStringSet(is,buff); + data.description = readString(is,buff); + } + } + + private void init(AuthzTrans trans) { + // the 3 is the number of key fields + String[] helpers = setCRUD(trans, TABLE, Data.class, PermLoader.deflt); + + // Other SELECT style statements... match with a local Method + psByType = new PSInfo(trans, SELECT_SP + helpers[FIELD_COMMAS] + " FROM " + TABLE + + " WHERE ns = ? AND type = ?", new PermLoader(2) { + @Override + protected void key(Data data, int idx, Object[] obj) { + obj[idx]=data.type; + } + },readConsistency); + + psNS = new PSInfo(trans, SELECT_SP + helpers[FIELD_COMMAS] + " FROM " + TABLE + + " WHERE ns = ?", new PermLoader(1),readConsistency); + + psChildren = new PSInfo(trans, SELECT_SP + helpers[FIELD_COMMAS] + " FROM " + TABLE + + " WHERE ns=? AND type > ? AND type < ?", + new PermLoader(3) { + @Override + protected void key(Data data, int _idx, Object[] obj) { + int idx = _idx; + obj[idx] = data.ns; + obj[++idx]=data.type + DOT; + obj[++idx]=data.type + DOT_PLUS_ONE; + } + },readConsistency); + + } + + + /** + * Add a single Permission to the Role's Permission Collection + * + * @param trans + * @param roleFullName + * @param perm + * @param type + * @param action + * @return + */ + public Result addRole(AuthzTrans trans, PermDAO.Data perm, String roleFullName) { + // Note: Prepared Statements for Collection updates aren't supported + //ResultSet rv = + try { + getSession(trans).execute(UPDATE_SP + TABLE + " SET roles = roles + {'" + roleFullName + "'} " + + "WHERE " + + "ns = '" + perm.ns + "' AND " + + "type = '" + perm.type + "' AND " + + "instance = '" + perm.instance + "' AND " + + "action = '" + perm.action + "';" + ); + } catch (DriverException | APIException | IOException e) { + reportPerhapsReset(trans,e); + return Result.err(Result.ERR_Backend, CassAccess.ERR_ACCESS_MSG); + } + + wasModified(trans, CRUD.update, perm, "Added role " + roleFullName + " to perm " + + perm.ns + '.' + perm.type + '|' + perm.instance + '|' + perm.action); + return Result.ok(); + } + + /** + * Remove a single Permission from the Role's Permission Collection + * @param trans + * @param roleFullName + * @param perm + * @param type + * @param action + * @return + */ + public Result delRole(AuthzTrans trans, PermDAO.Data perm, String roleFullName) { + // Note: Prepared Statements for Collection updates aren't supported + //ResultSet rv = + try { + getSession(trans).execute(UPDATE_SP + TABLE + " SET roles = roles - {'" + roleFullName + "'} " + + "WHERE " + + "ns = '" + perm.ns + "' AND " + + "type = '" + perm.type + "' AND " + + "instance = '" + perm.instance + "' AND " + + "action = '" + perm.action + "';" + ); + } catch (DriverException | APIException | IOException e) { + reportPerhapsReset(trans,e); + return Result.err(Result.ERR_Backend, CassAccess.ERR_ACCESS_MSG); + } + + //TODO how can we tell when it doesn't? + wasModified(trans, CRUD.update, perm, "Removed role " + roleFullName + " from perm " + + perm.ns + '.' + perm.type + '|' + perm.instance + '|' + perm.action); + return Result.ok(); + } + + + + /** + * Additional method: + * Select all Permissions by Name + * + * @param name + * @return + * @throws DAOException + */ + public Result> readByType(AuthzTrans trans, String ns, String type) { + return psByType.read(trans, R_TEXT, new Object[]{ns, type}); + } + + public Result> readChildren(AuthzTrans trans, String ns, String type) { + return psChildren.read(trans, R_TEXT, new Object[]{ns, type+DOT, type + DOT_PLUS_ONE}); + } + + public Result> readNS(AuthzTrans trans, String ns) { + return psNS.read(trans, R_TEXT, new Object[]{ns}); + } + + /** + * Add description to this permission + * + * @param trans + * @param ns + * @param type + * @param instance + * @param action + * @param description + * @return + */ + public Result addDescription(AuthzTrans trans, String ns, String type, + String instance, String action, String description) { + try { + getSession(trans).execute(UPDATE_SP + TABLE + " SET description = '" + + description + "' WHERE ns = '" + ns + "' AND type = '" + type + "'" + + "AND instance = '" + instance + "' AND action = '" + action + "';"); + } catch (DriverException | APIException | IOException e) { + reportPerhapsReset(trans,e); + return Result.err(Result.ERR_Backend, CassAccess.ERR_ACCESS_MSG); + } + + Data data = new Data(); + data.ns=ns; + data.type=type; + data.instance=instance; + data.action=action; + wasModified(trans, CRUD.update, data, "Added description " + description + " to permission " + + data.encode(), null ); + return Result.ok(); + } + + /** + * Log Modification statements to History + */ + @Override + protected void wasModified(AuthzTrans trans, CRUD modified, Data data, String ... override) { + boolean memo = override.length>0 && override[0]!=null; + boolean subject = override.length>1 && override[1]!=null; + + // Need to update history + HistoryDAO.Data hd = HistoryDAO.newInitedData(); + hd.user = trans.user(); + hd.action = modified.name(); + hd.target = TABLE; + hd.subject = subject ? override[1] : data.fullType(); + if (memo) { + hd.memo = String.format("%s", override[0]); + } else { + hd.memo = String.format("%sd %s|%s|%s", modified.name(),data.fullType(),data.instance,data.action); + } + + if(modified==CRUD.delete) { + try { + hd.reconstruct = data.bytify(); + } catch (IOException e) { + trans.error().log(e,"Could not serialize PermDAO.Data"); + } + } + + if(historyDAO.create(trans, hd).status!=Status.OK) { + trans.error().log("Cannot log to History"); + } + if(infoDAO.touch(trans, TABLE,data.invalidate(cache)).notOK()) { + trans.error().log("Cannot touch CacheInfo"); + } + } +} + diff --git a/auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/cass/RoleDAO.java b/auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/cass/RoleDAO.java new file mode 100644 index 00000000..da7d7a2d --- /dev/null +++ b/auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/cass/RoleDAO.java @@ -0,0 +1,412 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.dao.cass; + +import java.io.ByteArrayOutputStream; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.nio.ByteBuffer; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import org.onap.aaf.auth.dao.Bytification; +import org.onap.aaf.auth.dao.Cached; +import org.onap.aaf.auth.dao.CassAccess; +import org.onap.aaf.auth.dao.CassDAOImpl; +import org.onap.aaf.auth.dao.Loader; +import org.onap.aaf.auth.dao.Streamer; +import org.onap.aaf.auth.dao.hl.Question; +import org.onap.aaf.auth.env.AuthzTrans; +import org.onap.aaf.auth.layer.Result; +import org.onap.aaf.misc.env.APIException; +import org.onap.aaf.misc.env.util.Split; + +import com.datastax.driver.core.Cluster; +import com.datastax.driver.core.Row; +import com.datastax.driver.core.exceptions.DriverException; + +public class RoleDAO extends CassDAOImpl { + + public static final String TABLE = "role"; + public static final int CACHE_SEG = 0x40; // yields segment 0x0-0x3F + + private final HistoryDAO historyDAO; + private final CacheInfoDAO infoDAO; + + private PSInfo psChildren, psNS, psName; + + public RoleDAO(AuthzTrans trans, Cluster cluster, String keyspace) throws APIException, IOException { + super(trans, RoleDAO.class.getSimpleName(),cluster,keyspace,Data.class,TABLE, readConsistency(trans,TABLE), writeConsistency(trans,TABLE)); + // Set up sub-DAOs + historyDAO = new HistoryDAO(trans, this); + infoDAO = new CacheInfoDAO(trans,this); + init(trans); + } + + public RoleDAO(AuthzTrans trans, HistoryDAO hDAO, CacheInfoDAO ciDAO) { + super(trans, RoleDAO.class.getSimpleName(),hDAO,Data.class,TABLE, readConsistency(trans,TABLE), writeConsistency(trans,TABLE)); + historyDAO = hDAO; + infoDAO = ciDAO; + init(trans); + } + + + ////////////////////////////////////////// + // Data Definition, matches Cassandra DM + ////////////////////////////////////////// + private static final int KEYLIMIT = 2; + /** + * Data class that matches the Cassandra Table "role" + * @author Jonathan + */ + public static class Data extends CacheableData implements Bytification { + public String ns; + public String name; + public Set perms; + public String description; + + //////////////////////////////////////// + // Getters + public Set perms(boolean mutable) { + if (perms == null) { + perms = new HashSet(); + } else if (mutable && !(perms instanceof HashSet)) { + perms = new HashSet(perms); + } + return perms; + } + + public static Data create(NsDAO.Data ns, String name) { + NsSplit nss = new NsSplit(ns,name); + RoleDAO.Data rv = new Data(); + rv.ns = nss.ns; + rv.name=nss.name; + return rv; + } + + public String fullName() { + return ns + '.' + name; + } + + public String encode() { + return ns + '|' + name; + } + + /** + * Decode Perm String, including breaking into appropriate Namespace + * + * @param trans + * @param q + * @param r + * @return + */ + public static Result decode(AuthzTrans trans, Question q, String r) { + String[] ss = Split.splitTrim('|', r,2); + Data data = new Data(); + if(ss[1]==null) { // older 1 part encoding must be evaluated for NS + Result nss = q.deriveNsSplit(trans, ss[0]); + if(nss.notOK()) { + return Result.err(nss); + } + data.ns=nss.value.ns; + data.name=nss.value.name; + } else { // new 4 part encoding + data.ns=ss[0]; + data.name=ss[1]; + } + return Result.ok(data); + } + + /** + * Decode from UserRole Data + * @param urdd + * @return + */ + public static RoleDAO.Data decode(UserRoleDAO.Data urdd) { + RoleDAO.Data rd = new RoleDAO.Data(); + rd.ns = urdd.ns; + rd.name = urdd.rname; + return rd; + } + + + /** + * Decode Perm String, including breaking into appropriate Namespace + * + * @param trans + * @param q + * @param p + * @return + */ + public static Result decodeToArray(AuthzTrans trans, Question q, String p) { + String[] ss = Split.splitTrim('|', p,2); + if(ss[1]==null) { // older 1 part encoding must be evaluated for NS + Result nss = q.deriveNsSplit(trans, ss[0]); + if(nss.notOK()) { + return Result.err(nss); + } + ss[0] = nss.value.ns; + ss[1] = nss.value.name; + } + return Result.ok(ss); + } + + @Override + public int[] invalidate(Cached cache) { + return new int[] { + seg(cache,ns,name), + seg(cache,ns), + seg(cache,name), + }; + } + + @Override + public ByteBuffer bytify() throws IOException { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + RoleLoader.deflt.marshal(this,new DataOutputStream(baos)); + return ByteBuffer.wrap(baos.toByteArray()); + } + + @Override + public void reconstitute(ByteBuffer bb) throws IOException { + RoleLoader.deflt.unmarshal(this, toDIS(bb)); + } + + @Override + public String toString() { + return ns + '.' + name; + } + } + + private static class RoleLoader extends Loader implements Streamer { + public static final int MAGIC=923577343; + public static final int VERSION=1; + public static final int BUFF_SIZE=96; + + public static final RoleLoader deflt = new RoleLoader(KEYLIMIT); + + public RoleLoader(int keylimit) { + super(keylimit); + } + + @Override + public Data load(Data data, Row row) { + // Int more efficient + data.ns = row.getString(0); + data.name = row.getString(1); + data.perms = row.getSet(2,String.class); + data.description = row.getString(3); + return data; + } + + @Override + protected void key(Data data, int _idx, Object[] obj) { + int idx = _idx; + obj[idx]=data.ns; + obj[++idx]=data.name; + } + + @Override + protected void body(Data data, int _idx, Object[] obj) { + int idx = _idx; + obj[idx]=data.perms; + obj[++idx]=data.description; + } + + @Override + public void marshal(Data data, DataOutputStream os) throws IOException { + writeHeader(os,MAGIC,VERSION); + writeString(os, data.ns); + writeString(os, data.name); + writeStringSet(os,data.perms); + writeString(os, data.description); + } + + @Override + public void unmarshal(Data data, DataInputStream is) throws IOException { + /*int version = */readHeader(is,MAGIC,VERSION); + // If Version Changes between Production runs, you'll need to do a switch Statement, and adequately read in fields + byte[] buff = new byte[BUFF_SIZE]; + data.ns = readString(is, buff); + data.name = readString(is,buff); + data.perms = readStringSet(is,buff); + data.description = readString(is,buff); + } + }; + + private void init(AuthzTrans trans) { + String[] helpers = setCRUD(trans, TABLE, Data.class, RoleLoader.deflt); + + psNS = new PSInfo(trans, SELECT_SP + helpers[FIELD_COMMAS] + " FROM " + TABLE + + " WHERE ns = ?", new RoleLoader(1),readConsistency); + + psName = new PSInfo(trans, SELECT_SP + helpers[FIELD_COMMAS] + " FROM " + TABLE + + " WHERE name = ?", new RoleLoader(1),readConsistency); + + psChildren = new PSInfo(trans, SELECT_SP + helpers[FIELD_COMMAS] + " FROM " + TABLE + + " WHERE ns=? AND name > ? AND name < ?", + new RoleLoader(3) { + @Override + protected void key(Data data, int _idx, Object[] obj) { + int idx = _idx; + obj[idx] = data.ns; + obj[++idx]=data.name + DOT; + obj[++idx]=data.name + DOT_PLUS_ONE; + } + },readConsistency); + + } + + public Result> readNS(AuthzTrans trans, String ns) { + return psNS.read(trans, R_TEXT + " NS " + ns, new Object[]{ns}); + } + + public Result> readName(AuthzTrans trans, String name) { + return psName.read(trans, R_TEXT + name, new Object[]{name}); + } + + public Result> readChildren(AuthzTrans trans, String ns, String role) { + if(role.length()==0 || "*".equals(role)) { + return psChildren.read(trans, R_TEXT, new Object[]{ns, FIRST_CHAR, LAST_CHAR}); + } else { + return psChildren.read(trans, R_TEXT, new Object[]{ns, role+DOT, role+DOT_PLUS_ONE}); + } + } + + /** + * Add a single Permission to the Role's Permission Collection + * + * @param trans + * @param role + * @param perm + * @param type + * @param action + * @return + */ + public Result addPerm(AuthzTrans trans, RoleDAO.Data role, PermDAO.Data perm) { + // Note: Prepared Statements for Collection updates aren't supported + String pencode = perm.encode(); + try { + getSession(trans).execute(UPDATE_SP + TABLE + " SET perms = perms + {'" + + pencode + "'} WHERE " + + "ns = '" + role.ns + "' AND name = '" + role.name + "';"); + } catch (DriverException | APIException | IOException e) { + reportPerhapsReset(trans,e); + return Result.err(Result.ERR_Backend, CassAccess.ERR_ACCESS_MSG); + } + + wasModified(trans, CRUD.update, role, "Added permission " + pencode + " to role " + role.fullName()); + return Result.ok(); + } + + /** + * Remove a single Permission from the Role's Permission Collection + * @param trans + * @param role + * @param perm + * @param type + * @param action + * @return + */ + public Result delPerm(AuthzTrans trans, RoleDAO.Data role, PermDAO.Data perm) { + // Note: Prepared Statements for Collection updates aren't supported + + String pencode = perm.encode(); + + //ResultSet rv = + try { + getSession(trans).execute(UPDATE_SP + TABLE + " SET perms = perms - {'" + + pencode + "'} WHERE " + + "ns = '" + role.ns + "' AND name = '" + role.name + "';"); + } catch (DriverException | APIException | IOException e) { + reportPerhapsReset(trans,e); + return Result.err(Result.ERR_Backend, CassAccess.ERR_ACCESS_MSG); + } + + //TODO how can we tell when it doesn't? + wasModified(trans, CRUD.update, role, "Removed permission " + pencode + " from role " + role.fullName() ); + return Result.ok(); + } + + /** + * Add description to role + * + * @param trans + * @param ns + * @param name + * @param description + * @return + */ + public Result addDescription(AuthzTrans trans, String ns, String name, String description) { + try { + getSession(trans).execute(UPDATE_SP + TABLE + " SET description = '" + + description + "' WHERE ns = '" + ns + "' AND name = '" + name + "';"); + } catch (DriverException | APIException | IOException e) { + reportPerhapsReset(trans,e); + return Result.err(Result.ERR_Backend, CassAccess.ERR_ACCESS_MSG); + } + + Data data = new Data(); + data.ns=ns; + data.name=name; + wasModified(trans, CRUD.update, data, "Added description " + description + " to role " + data.fullName(), null ); + return Result.ok(); + } + + + /** + * Log Modification statements to History + * @param modified which CRUD action was done + * @param data entity data that needs a log entry + * @param overrideMessage if this is specified, we use it rather than crafting a history message based on data + */ + @Override + protected void wasModified(AuthzTrans trans, CRUD modified, Data data, String ... override) { + boolean memo = override.length>0 && override[0]!=null; + boolean subject = override.length>1 && override[1]!=null; + + HistoryDAO.Data hd = HistoryDAO.newInitedData(); + hd.user = trans.user(); + hd.action = modified.name(); + hd.target = TABLE; + hd.subject = subject ? override[1] : data.fullName(); + hd.memo = memo ? override[0] : (data.fullName() + " was " + modified.name() + 'd' ); + if(modified==CRUD.delete) { + try { + hd.reconstruct = data.bytify(); + } catch (IOException e) { + trans.error().log(e,"Could not serialize RoleDAO.Data"); + } + } + + if(historyDAO.create(trans, hd).status!=Status.OK) { + trans.error().log("Cannot log to History"); + } + if(infoDAO.touch(trans, TABLE,data.invalidate(cache)).notOK()) { + trans.error().log("Cannot touch CacheInfo for Role"); + } + } + + +} \ No newline at end of file diff --git a/auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/cass/Status.java b/auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/cass/Status.java new file mode 100644 index 00000000..be52c406 --- /dev/null +++ b/auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/cass/Status.java @@ -0,0 +1,88 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.dao.cass; + +import org.onap.aaf.auth.layer.Result; + + + + +/** + * Add additional Behavior for Specific Applications for Results + * + * In this case, we add additional BitField information accessible by + * method ( + * @author Jonathan + * + * @param + */ +public class Status extends Result { + + // Jonathan 10/1/2013: Initially, I used enum, but it's not extensible. + public final static int ERR_NsNotFound = Result.ERR_General+1, + ERR_RoleNotFound = Result.ERR_General+2, + ERR_PermissionNotFound = Result.ERR_General+3, + ERR_UserNotFound = Result.ERR_General+4, + ERR_UserRoleNotFound = Result.ERR_General+5, + ERR_DelegateNotFound = Result.ERR_General+6, + ERR_InvalidDelegate = Result.ERR_General+7, + ERR_DependencyExists = Result.ERR_General+8, + ERR_NoApprovals = Result.ERR_General+9, + ACC_Now = Result.ERR_General+10, + ACC_Future = Result.ERR_General+11, + ERR_ChoiceNeeded = Result.ERR_General+12, + ERR_FutureNotRequested = Result.ERR_General+13; + + /** + * Constructor for Result set. + * @param data + * @param status + */ + private Status(RV value, int status, String details, String[] variables ) { + super(value,status,details,variables); + } + + public static String name(int status) { + switch(status) { + case OK: return "OK"; + case ERR_NsNotFound: return "ERR_NsNotFound"; + case ERR_RoleNotFound: return "ERR_RoleNotFound"; + case ERR_PermissionNotFound: return "ERR_PermissionNotFound"; + case ERR_UserNotFound: return "ERR_UserNotFound"; + case ERR_UserRoleNotFound: return "ERR_UserRoleNotFound"; + case ERR_DelegateNotFound: return "ERR_DelegateNotFound"; + case ERR_InvalidDelegate: return "ERR_InvalidDelegate"; + case ERR_ConflictAlreadyExists: return "ERR_ConflictAlreadyExists"; + case ERR_DependencyExists: return "ERR_DependencyExists"; + case ERR_ActionNotCompleted: return "ERR_ActionNotCompleted"; + case ERR_Denied: return "ERR_Denied"; + case ERR_Policy: return "ERR_Policy"; + case ERR_BadData: return "ERR_BadData"; + case ERR_NotImplemented: return "ERR_NotImplemented"; + case ERR_NotFound: return "ERR_NotFound"; + case ERR_ChoiceNeeded: return "ERR_ChoiceNeeded"; + } + //case ERR_General: or unknown... + return "ERR_General"; + } + +} diff --git a/auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/cass/UserRoleDAO.java b/auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/cass/UserRoleDAO.java new file mode 100644 index 00000000..301e47fc --- /dev/null +++ b/auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/cass/UserRoleDAO.java @@ -0,0 +1,319 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.dao.cass; + +import java.io.ByteArrayOutputStream; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.nio.ByteBuffer; +import java.util.Date; +import java.util.List; + +import org.onap.aaf.auth.dao.Bytification; +import org.onap.aaf.auth.dao.Cached; +import org.onap.aaf.auth.dao.CassDAOImpl; +import org.onap.aaf.auth.dao.DAOException; +import org.onap.aaf.auth.dao.Loader; +import org.onap.aaf.auth.dao.Streamer; +import org.onap.aaf.auth.dao.hl.Question; +import org.onap.aaf.auth.env.AuthzTrans; +import org.onap.aaf.auth.layer.Result; +import org.onap.aaf.misc.env.APIException; +import org.onap.aaf.misc.env.Slot; +import org.onap.aaf.misc.env.util.Chrono; + +import com.datastax.driver.core.Cluster; +import com.datastax.driver.core.Row; + +public class UserRoleDAO extends CassDAOImpl { + public static final String TABLE = "user_role"; + + public static final int CACHE_SEG = 0x40; // yields segment 0x0-0x3F + + private static final String TRANS_UR_SLOT = "_TRANS_UR_SLOT_"; + public Slot transURSlot; + + private final HistoryDAO historyDAO; + private final CacheInfoDAO infoDAO; + + private PSInfo psByUser, psByRole, psUserInRole; + + + + public UserRoleDAO(AuthzTrans trans, Cluster cluster, String keyspace) throws APIException, IOException { + super(trans, UserRoleDAO.class.getSimpleName(),cluster,keyspace,Data.class,TABLE, readConsistency(trans,TABLE), writeConsistency(trans,TABLE)); + transURSlot = trans.slot(TRANS_UR_SLOT); + init(trans); + + // Set up sub-DAOs + historyDAO = new HistoryDAO(trans, this); + infoDAO = new CacheInfoDAO(trans,this); + } + + public UserRoleDAO(AuthzTrans trans, HistoryDAO hDAO, CacheInfoDAO ciDAO) { + super(trans, UserRoleDAO.class.getSimpleName(),hDAO,Data.class,TABLE, readConsistency(trans,TABLE), writeConsistency(trans,TABLE)); + transURSlot = trans.slot(TRANS_UR_SLOT); + historyDAO = hDAO; + infoDAO = ciDAO; + init(trans); + } + + private static final int KEYLIMIT = 2; + public static class Data extends CacheableData implements Bytification { + public String user; + public String role; + public String ns; + public String rname; + public Date expires; + + @Override + public int[] invalidate(Cached cache) { + // Note: I'm not worried about Name collisions, because the formats are different: + // Jonathan... etc versus + // com. ... + // The "dot" makes the difference. + return new int[] { + seg(cache,user,role), + seg(cache,user), + seg(cache,role) + }; + } + + @Override + public ByteBuffer bytify() throws IOException { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + URLoader.deflt.marshal(this,new DataOutputStream(baos)); + return ByteBuffer.wrap(baos.toByteArray()); + } + + @Override + public void reconstitute(ByteBuffer bb) throws IOException { + URLoader.deflt.unmarshal(this, toDIS(bb)); + } + + public void role(String ns, String rname) { + this.ns = ns; + this.rname = rname; + this.role = ns + '.' + rname; + } + + public void role(RoleDAO.Data rdd) { + ns = rdd.ns; + rname = rdd.name; + role = rdd.fullName(); + } + + + public boolean role(AuthzTrans trans, Question ques, String role) { + this.role = role; + Result rnss = ques.deriveNsSplit(trans, role); + if(rnss.isOKhasData()) { + ns = rnss.value.ns; + rname = rnss.value.name; + return true; + } else { + return false; + } + } + + @Override + public String toString() { + return user + '|' + ns + '|' + rname + '|' + Chrono.dateStamp(expires); + } + + + } + + private static class URLoader extends Loader implements Streamer { + public static final int MAGIC=738469903; + public static final int VERSION=1; + public static final int BUFF_SIZE=48; + + public static final URLoader deflt = new URLoader(KEYLIMIT); + + public URLoader(int keylimit) { + super(keylimit); + } + + @Override + public Data load(Data data, Row row) { + data.user = row.getString(0); + data.role = row.getString(1); + data.ns = row.getString(2); + data.rname = row.getString(3); + data.expires = row.getTimestamp(4); + return data; + } + + @Override + protected void key(Data data, int _idx, Object[] obj) { + int idx = _idx; + obj[idx]=data.user; + obj[++idx]=data.role; + } + + @Override + protected void body(Data data, int _idx, Object[] obj) { + int idx = _idx; + obj[idx]=data.ns; + obj[++idx]=data.rname; + obj[++idx]=data.expires; + } + + @Override + public void marshal(Data data, DataOutputStream os) throws IOException { + writeHeader(os,MAGIC,VERSION); + + writeString(os, data.user); + writeString(os, data.role); + writeString(os, data.ns); + writeString(os, data.rname); + os.writeLong(data.expires==null?-1:data.expires.getTime()); + } + + @Override + public void unmarshal(Data data, DataInputStream is) throws IOException { + /*int version = */readHeader(is,MAGIC,VERSION); + // If Version Changes between Production runs, you'll need to do a switch Statement, and adequately read in fields + + byte[] buff = new byte[BUFF_SIZE]; + data.user = readString(is,buff); + data.role = readString(is,buff); + data.ns = readString(is,buff); + data.rname = readString(is,buff); + long l = is.readLong(); + data.expires = l<0?null:new Date(l); + } + + }; + + private void init(AuthzTrans trans) { + String[] helper = setCRUD(trans, TABLE, Data.class, URLoader.deflt); + + psByUser = new PSInfo(trans, SELECT_SP + helper[FIELD_COMMAS] + " FROM user_role WHERE user = ?", + new URLoader(1) { + @Override + protected void key(Data data, int idx, Object[] obj) { + obj[idx]=data.user; + } + },readConsistency); + + // Note: We understand this call may have poor performance, so only should be used in Management (Delete) func + psByRole = new PSInfo(trans, SELECT_SP + helper[FIELD_COMMAS] + " FROM user_role WHERE role = ? ALLOW FILTERING", + new URLoader(1) { + @Override + protected void key(Data data, int idx, Object[] obj) { + obj[idx]=data.role; + } + },readConsistency); + + psUserInRole = new PSInfo(trans,SELECT_SP + helper[FIELD_COMMAS] + " FROM user_role WHERE user = ? AND role = ?", + URLoader.deflt,readConsistency); + } + + public Result> readByUser(AuthzTrans trans, String user) { + return psByUser.read(trans, R_TEXT + " by User " + user, new Object[]{user}); + } + + /** + * Note: Use Sparingly. Cassandra's forced key structure means this will perform fairly poorly + * @param trans + * @param role + * @return + * @throws DAOException + */ + public Result> readByRole(AuthzTrans trans, String role) { + return psByRole.read(trans, R_TEXT + " by Role " + role, new Object[]{role}); + } + + /** + * Direct Lookup of User Role + * Don't forget to check for Expiration + */ + public Result> readByUserRole(AuthzTrans trans, String user, String role) { + return psUserInRole.read(trans, R_TEXT + " by User " + user + " and Role " + role, new Object[]{user,role}); + } + + + /** + * Log Modification statements to History + * @param modified which CRUD action was done + * @param data entity data that needs a log entry + * @param overrideMessage if this is specified, we use it rather than crafting a history message based on data + */ + @Override + protected void wasModified(AuthzTrans trans, CRUD modified, Data data, String ... override) { + boolean memo = override.length>0 && override[0]!=null; + boolean subject = override.length>1 && override[1]!=null; + + HistoryDAO.Data hd = HistoryDAO.newInitedData(); + HistoryDAO.Data hdRole = HistoryDAO.newInitedData(); + + hd.user = hdRole.user = trans.user(); + hd.action = modified.name(); + // Modifying User/Role is an Update to Role, not a Create. Jonathan, 07-14-2015 + hdRole.action = CRUD.update.name(); + hd.target = TABLE; + hdRole.target = RoleDAO.TABLE; + hd.subject = subject?override[1] : (data.user + '|'+data.role); + hdRole.subject = data.role; + switch(modified) { + case create: + hd.memo = hdRole.memo = memo + ? String.format("%s by %s", override[0], hd.user) + : String.format("%s added to %s",data.user,data.role); + break; + case update: + hd.memo = hdRole.memo = memo + ? String.format("%s by %s", override[0], hd.user) + : String.format("%s - %s was updated",data.user,data.role); + break; + case delete: + hd.memo = hdRole.memo = memo + ? String.format("%s by %s", override[0], hd.user) + : String.format("%s removed from %s",data.user,data.role); + try { + hd.reconstruct = hdRole.reconstruct = data.bytify(); + } catch (IOException e) { + trans.warn().log(e,"Deleted UserRole could not be serialized"); + } + break; + default: + hd.memo = hdRole.memo = memo + ? String.format("%s by %s", override[0], hd.user) + : "n/a"; + } + + if(historyDAO.create(trans, hd).status!=Status.OK) { + trans.error().log("Cannot log to History"); + } + + if(historyDAO.create(trans, hdRole).status!=Status.OK) { + trans.error().log("Cannot log to History"); + } + // uses User as Segment + if(infoDAO.touch(trans, TABLE,data.invalidate(cache)).notOK()) { + trans.error().log("Cannot touch CacheInfo"); + } + } +} diff --git a/auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/hl/CassExecutor.java b/auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/hl/CassExecutor.java new file mode 100644 index 00000000..1979db28 --- /dev/null +++ b/auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/hl/CassExecutor.java @@ -0,0 +1,73 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.dao.hl; + +import org.onap.aaf.auth.dao.cass.NsSplit; +import org.onap.aaf.auth.dao.cass.NsDAO.Data; +import org.onap.aaf.auth.env.AuthzTrans; +import org.onap.aaf.auth.layer.Result; +import org.onap.aaf.auth.org.Executor; + +public class CassExecutor implements Executor { + + private Question q; + private Function f; + private AuthzTrans trans; + + public CassExecutor(AuthzTrans trans, Function f) { + this.trans = trans; + this.f = f; + this.q = this.f.q; + } + + @Override + public boolean hasPermission(String user, String ns, String type, String instance, String action) { + return isGranted(user, ns, type, instance, action); + } + + @Override + public boolean inRole(String name) { + Result nss = q.deriveNsSplit(trans, name); + if(nss.notOK())return false; + return q.roleDAO.read(trans, nss.value.ns,nss.value.name).isOKhasData(); + } + + public boolean isGranted(String user, String ns, String type, String instance, String action) { + return q.isGranted(trans, user, ns, type, instance,action); + } + + @Override + public String namespace() throws Exception { + Result res = q.validNSOfDomain(trans,trans.user()); + if(res.isOK()) { + String user[] = trans.user().split("\\."); + return user[user.length-1] + '.' + user[user.length-2]; + } + throw new Exception(res.status + ' ' + res.details); + } + + @Override + public String id() { + return trans.user(); + } + +} diff --git a/auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/hl/Function.java b/auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/hl/Function.java new file mode 100644 index 00000000..1f679075 --- /dev/null +++ b/auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/hl/Function.java @@ -0,0 +1,1792 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.dao.hl; + +import static org.onap.aaf.auth.layer.Result.OK; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Date; +import java.util.GregorianCalendar; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.UUID; + +import org.onap.aaf.auth.common.Define; +import org.onap.aaf.auth.dao.DAOException; +import org.onap.aaf.auth.dao.cass.ApprovalDAO; +import org.onap.aaf.auth.dao.cass.CredDAO; +import org.onap.aaf.auth.dao.cass.DelegateDAO; +import org.onap.aaf.auth.dao.cass.FutureDAO; +import org.onap.aaf.auth.dao.cass.Namespace; +import org.onap.aaf.auth.dao.cass.NsDAO; +import org.onap.aaf.auth.dao.cass.NsSplit; +import org.onap.aaf.auth.dao.cass.NsType; +import org.onap.aaf.auth.dao.cass.PermDAO; +import org.onap.aaf.auth.dao.cass.RoleDAO; +import org.onap.aaf.auth.dao.cass.Status; +import org.onap.aaf.auth.dao.cass.UserRoleDAO; +import org.onap.aaf.auth.dao.cass.NsDAO.Data; +import org.onap.aaf.auth.dao.hl.Question.Access; +import org.onap.aaf.auth.env.AuthzTrans; +import org.onap.aaf.auth.env.AuthzTrans.REQD_TYPE; +import org.onap.aaf.auth.layer.Result; +import org.onap.aaf.auth.org.Executor; +import org.onap.aaf.auth.org.Organization; +import org.onap.aaf.auth.org.OrganizationException; +import org.onap.aaf.auth.org.Organization.Expiration; +import org.onap.aaf.auth.org.Organization.Identity; +import org.onap.aaf.auth.org.Organization.Policy; + +public class Function { + + private static final String CANNOT_BE_THE_OWNER_OF_A_NAMESPACE = "%s(%s) cannot be the owner of the namespace '%s'. Owners %s."; + + public enum FUTURE_OP { + C("Create"),U("Update"),D("Delete"),G("Grant"),UG("UnGrant"),A("Approval"); + + private String desc; + + private FUTURE_OP(String desc) { + this.desc = desc; + } + + public String desc() { + return desc; + } + + /** + * Same as valueOf(), but passes back null instead of throwing Exception + * @param value + * @return + */ + public static FUTURE_OP toFO(String value) { + if(value!=null) { + for(FUTURE_OP fo : values()) { + if(fo.name().equals(value)){ + return fo; + } + } + } + return null; + } + } + + public enum OP_STATUS { + E("Executed"),D("Denied"),P("Pending"),L("Lapsed"); + + private String desc; + public final static Result RE = Result.ok(OP_STATUS.E); + public final static Result RD = Result.ok(OP_STATUS.D); + public final static Result RP = Result.ok(OP_STATUS.P); + public final static Result RL = Result.ok(OP_STATUS.L); + + private OP_STATUS(String desc) { + this.desc = desc; + } + + public String desc() { + return desc; + } + + } + + public static final String FOP_CRED = "cred"; + public static final String FOP_DELEGATE = "delegate"; + public static final String FOP_NS = "ns"; + public static final String FOP_PERM = "perm"; + public static final String FOP_ROLE = "role"; + public static final String FOP_USER_ROLE = "user_role"; + private static final List NO_ADDL_APPROVE = new ArrayList(); + private static final String ROOT_NS = Define.ROOT_NS(); + // First Action should ALWAYS be "write", see "CreateRole" + public final Question q; + + public Function(AuthzTrans trans, Question question) { + q = question; + } + + private class ErrBuilder { + private StringBuilder sb; + private List ao; + + public void log(Result result) { + if (result.notOK()) { + if (sb == null) { + sb = new StringBuilder(); + ao = new ArrayList(); + } + sb.append(result.details); + sb.append('\n'); + for (String s : result.variables) { + ao.add(s); + } + } + } + + public String[] vars() { + String[] rv = new String[ao.size()]; + ao.toArray(rv); + return rv; + } + + public boolean hasErr() { + return sb != null; + } + + @Override + public String toString() { + return sb == null ? "" : String.format(sb.toString(), ao); + } + } + + /** + * createNS + * + * Create Namespace + * + * @param trans + * @param org + * @param ns + * @param user + * @return + * @throws DAOException + * + * To create an NS, you need to: 1) validate permission to + * modify parent NS 2) Does NS exist already? 3) Create NS with + * a) "user" as owner. NOTE: Per 10-15 request for AAF 1.0 4) + * Loop through Roles with Parent NS, and map any that start + * with this NS into this one 5) Loop through Perms with Parent + * NS, and map any that start with this NS into this one + */ + public Result createNS(AuthzTrans trans, Namespace namespace, boolean fromApproval) { + Result rq; +// if (namespace.name.endsWith(Question.DOT_ADMIN) +// || namespace.name.endsWith(Question.DOT_OWNER)) { +// return Result.err(Status.ERR_BadData, +// "'admin' and 'owner' are reserved names in AAF"); +// } + + try { + for (String u : namespace.owner) { + Organization org = trans.org(); + Identity orgUser = org.getIdentity(trans, u); + String reason; + if (orgUser == null) { + return Result.err(Status.ERR_Policy,"%s is not a valid user at %s",u,org.getName()); + } else if((reason=orgUser.mayOwn())!=null) { + if (org.isTestEnv()) { + String reason2; + if((reason2=org.validate(trans, Policy.AS_RESPONSIBLE,new CassExecutor(trans, this), u))!=null) { // can masquerade as responsible + trans.debug().log(reason2); + return Result.err(Status.ERR_Policy,CANNOT_BE_THE_OWNER_OF_A_NAMESPACE,orgUser.fullName(),orgUser.id(),namespace.name,reason); + } + // a null means ok + } else { + if(orgUser.isFound()) { + return Result.err(Status.ERR_Policy,CANNOT_BE_THE_OWNER_OF_A_NAMESPACE,orgUser.fullName(),orgUser.id(),namespace.name, reason); + } else { + return Result.err(Status.ERR_Policy,u + " is an invalid Identity"); + } + } + } + } + } catch (Exception e) { + trans.error().log(e, + "Could not contact Organization for User Validation"); + } + + String user = trans.user(); + // 1) May Change Parent? + int idx = namespace.name.lastIndexOf('.'); + String parent; + if (idx < 0) { + if (!q.isGranted(trans, user, ROOT_NS,Question.NS, ".", "create")) { + return Result.err(Result.ERR_Security, + "%s may not create Root Namespaces", user); + } + parent = null; + fromApproval = true; + } else { + parent = namespace.name.substring(0, idx); // get Parent String + } + + Result rparent = q.deriveNs(trans, parent); + if (rparent.notOK()) { + return Result.err(rparent); + } + if (!fromApproval) { + rparent = q.mayUser(trans, user, rparent.value, Access.write); + if (rparent.notOK()) { + return Result.err(rparent); + } + } + parent = namespace.parent = rparent.value.name; // Correct Namespace from real data + + // 2) Does requested NS exist + if (q.nsDAO.read(trans, namespace.name).isOKhasData()) { + return Result.err(Status.ERR_ConflictAlreadyExists, + "Target Namespace already exists"); + } + + // Someone must be responsible. + if (namespace.owner == null || namespace.owner.isEmpty()) { + return Result + .err(Status.ERR_Policy, + "Namespaces must be assigned at least one responsible party"); + } + + // 3) Create NS + Date now = new Date(); + + Result r; + // 3a) Admin + + try { + // Originally, added the enterer as Admin, but that's not necessary, + // or helpful for Operations folks.. + // Admins can be empty, because they can be changed by lower level + // NSs + // if(ns.admin(false).isEmpty()) { + // ns.admin(true).add(user); + // } + if (namespace.admin != null) { + for (String u : namespace.admin) { + if ((r = checkValidID(trans, now, u)).notOK()) { + return r; + } + } + } + + // 3b) Responsible + Organization org = trans.org(); + for (String u : namespace.owner) { + Identity orgUser = org.getIdentity(trans, u); + if (orgUser == null) { + return Result + .err(Status.ERR_BadData, + "NS must be created with an %s approved Responsible Party", + org.getName()); + } + } + } catch (Exception e) { + return Result.err(Status.ERR_UserNotFound, e.getMessage()); + } + + // VALIDATIONS done... Add NS + if ((rq = q.nsDAO.create(trans, namespace.data())).notOK()) { + return Result.err(rq); + } + + // Since Namespace is now created, we need to grab all subsequent errors + ErrBuilder eb = new ErrBuilder(); + + // Add UserRole(s) + UserRoleDAO.Data urdd = new UserRoleDAO.Data(); + urdd.expires = trans.org().expiration(null, Expiration.UserInRole).getTime(); + urdd.role(namespace.name, Question.ADMIN); + for (String admin : namespace.admin) { + urdd.user = admin; + eb.log(q.userRoleDAO.create(trans, urdd)); + } + urdd.role(namespace.name,Question.OWNER); + for (String owner : namespace.owner) { + urdd.user = owner; + eb.log(q.userRoleDAO.create(trans, urdd)); + } + + addNSAdminRolesPerms(trans, eb, namespace.name); + + addNSOwnerRolesPerms(trans, eb, namespace.name); + + if (parent != null) { + // Build up with any errors + + String targetNs = rparent.value.name; // Get the Parent Namespace, + // not target + String targetName = namespace.name.substring(targetNs.length() + 1); // Remove the Parent Namespace from the + // Target + a dot, and you'll get the name + int targetNameDot = targetName.length() + 1; + + // 4) Change any roles with children matching this NS, and + Result> rrdc = q.roleDAO.readChildren(trans, targetNs, targetName); + if (rrdc.isOKhasData()) { + for (RoleDAO.Data rdd : rrdc.value) { + // Remove old Role from Perms, save them off + List lpdd = new ArrayList(); + for(String p : rdd.perms(false)) { + Result rpdd = PermDAO.Data.decode(trans,q,p); + if(rpdd.isOKhasData()) { + PermDAO.Data pdd = rpdd.value; + lpdd.add(pdd); + q.permDAO.delRole(trans, pdd, rdd); + } else{ + trans.error().log(rpdd.errorString()); + } + } + + // Save off Old keys + String delP1 = rdd.ns; + String delP2 = rdd.name; + + // Write in new key + rdd.ns = namespace.name; + rdd.name = (delP2.length() > targetNameDot) ? delP2 + .substring(targetNameDot) : ""; + + // Need to use non-cached, because switching namespaces, not + // "create" per se + if ((rq = q.roleDAO.create(trans, rdd)).isOK()) { + // Put Role back into Perm, with correct info + for(PermDAO.Data pdd : lpdd) { + q.permDAO.addRole(trans, pdd, rdd); + } + // Change data for User Roles + Result> rurd = q.userRoleDAO.readByRole(trans, rdd.fullName()); + if(rurd.isOKhasData()) { + for(UserRoleDAO.Data urd : rurd.value) { + urd.ns = rdd.ns; + urd.rname = rdd.name; + q.userRoleDAO.update(trans, urd); + } + } + // Now delete old one + rdd.ns = delP1; + rdd.name = delP2; + if ((rq = q.roleDAO.delete(trans, rdd, false)).notOK()) { + eb.log(rq); + } + } else { + eb.log(rq); + } + } + } + + // 4) Change any Permissions with children matching this NS, and + Result> rpdc = q.permDAO.readChildren(trans,targetNs, targetName); + if (rpdc.isOKhasData()) { + for (PermDAO.Data pdd : rpdc.value) { + // Remove old Perm from Roles, save them off + List lrdd = new ArrayList(); + + for(String rl : pdd.roles(false)) { + Result rrdd = RoleDAO.Data.decode(trans,q,rl); + if(rrdd.isOKhasData()) { + RoleDAO.Data rdd = rrdd.value; + lrdd.add(rdd); + q.roleDAO.delPerm(trans, rdd, pdd); + } else{ + trans.error().log(rrdd.errorString()); + } + } + + // Save off Old keys + String delP1 = pdd.ns; + String delP2 = pdd.type; + pdd.ns = namespace.name; + pdd.type = (delP2.length() > targetNameDot) ? delP2 + .substring(targetNameDot) : ""; + if ((rq = q.permDAO.create(trans, pdd)).isOK()) { + // Put Role back into Perm, with correct info + for(RoleDAO.Data rdd : lrdd) { + q.roleDAO.addPerm(trans, rdd, pdd); + } + + pdd.ns = delP1; + pdd.type = delP2; + if ((rq = q.permDAO.delete(trans, pdd, false)).notOK()) { + eb.log(rq); + // } else { + // Need to invalidate directly, because we're + // switching places in NS, not normal cache behavior + // q.permDAO.invalidate(trans,pdd); + } + } else { + eb.log(rq); + } + } + } + if (eb.hasErr()) { + return Result.err(Status.ERR_ActionNotCompleted,eb.sb.toString(), eb.vars()); + } + } + return Result.ok(); + } + + private void addNSAdminRolesPerms(AuthzTrans trans, ErrBuilder eb, String ns) { + // Admin Role/Perm + RoleDAO.Data rd = new RoleDAO.Data(); + rd.ns = ns; + rd.name = "admin"; + rd.description = "AAF Namespace Administrators"; + + PermDAO.Data pd = new PermDAO.Data(); + pd.ns = ns; + pd.type = "access"; + pd.instance = Question.ASTERIX; + pd.action = Question.ASTERIX; + pd.description = "AAF Namespace Write Access"; + + rd.perms = new HashSet(); + rd.perms.add(pd.encode()); + eb.log(q.roleDAO.create(trans, rd)); + + pd.roles = new HashSet(); + pd.roles.add(rd.encode()); + eb.log(q.permDAO.create(trans, pd)); + } + + private void addNSOwnerRolesPerms(AuthzTrans trans, ErrBuilder eb, String ns) { + RoleDAO.Data rd = new RoleDAO.Data(); + rd.ns = ns; + rd.name = "owner"; + rd.description = "AAF Namespace Owners"; + + PermDAO.Data pd = new PermDAO.Data(); + pd.ns = ns; + pd.type = "access"; + pd.instance = Question.ASTERIX; + pd.action = Question.READ; + pd.description = "AAF Namespace Read Access"; + + rd.perms = new HashSet(); + rd.perms.add(pd.encode()); + eb.log(q.roleDAO.create(trans, rd)); + + pd.roles = new HashSet(); + pd.roles.add(rd.encode()); + eb.log(q.permDAO.create(trans, pd)); + } + + /** + * deleteNS + * + * Delete Namespace + * + * @param trans + * @param org + * @param ns + * @param force + * @param user + * @return + * @throws DAOException + * + * + * To delete an NS, you need to: 1) validate permission to + * modify this NS 2) Find all Roles with this NS, and 2a) if + * Force, delete them, else modify to Parent NS 3) Find all + * Perms with this NS, and modify to Parent NS 3a) if Force, + * delete them, else modify to Parent NS 4) Find all IDs + * associated to this NS, and deny if exists. 5) Remove NS + */ + public Result deleteNS(AuthzTrans trans, String ns) { + boolean force = trans.requested(REQD_TYPE.force); + boolean move = trans.requested(REQD_TYPE.move); + // 1) Validate + Result> nsl; + if ((nsl = q.nsDAO.read(trans, ns)).notOKorIsEmpty()) { + return Result.err(Status.ERR_NsNotFound, "%s does not exist", ns); + } + NsDAO.Data nsd = nsl.value.get(0); + NsType nt; + if (move && !q.canMove(nt = NsType.fromType(nsd.type))) { + return Result.err(Status.ERR_Denied, "Namespace Force=move not permitted for Type %s",nt.name()); + } + + Result dnr = q.mayUser(trans, trans.user(), nsd, Access.write); + if (dnr.status != Status.OK) { + return Result.err(dnr); + } + + // 2) Find Parent + String user = trans.user(); + int idx = ns.lastIndexOf('.'); + NsDAO.Data parent; + if (idx < 0) { + if (!q.isGranted(trans, user, ROOT_NS,Question.NS, ".", "delete")) { + return Result.err(Result.ERR_Security, + "%s may not delete Root Namespaces", user); + } + parent = null; + } else { + Result rlparent = q.deriveNs(trans, ns.substring(0, idx)); + if (rlparent.notOKorIsEmpty()) { + return Result.err(rlparent); + } + parent = rlparent.value; + } + + // Build up with any errors + // If sb != null below is an indication of error + StringBuilder sb = null; + ErrBuilder er = new ErrBuilder(); + + // 2a) Deny if any IDs on Namespace + Result> creds = q.credDAO.readNS(trans, ns); + if (creds.isOKhasData()) { + if (force || move) { + for (CredDAO.Data cd : creds.value) { + er.log(q.credDAO.delete(trans, cd, false)); + // Since we're deleting all the creds, we should delete all + // the user Roles for that Cred + Result> rlurd = q.userRoleDAO + .readByUser(trans, cd.id); + if (rlurd.isOK()) { + for (UserRoleDAO.Data data : rlurd.value) { + q.userRoleDAO.delete(trans, data, false); + } + } + + } + } else { + // first possible StringBuilder Create. + sb = new StringBuilder(); + sb.append('['); + sb.append(ns); + sb.append("] contains users"); + } + } + + // 2b) Find (or delete if forced flag is set) dependencies + // First, find if NS Perms are the only ones + Result> rpdc = q.permDAO.readNS(trans, ns); + if (rpdc.isOKhasData()) { + // Since there are now NS perms, we have to count NON-NS perms. + // FYI, if we delete them now, and the NS is not deleted, it is in + // an inconsistent state. + boolean nonaccess = false; + for (PermDAO.Data pdd : rpdc.value) { + if (!"access".equals(pdd.type)) { + nonaccess = true; + break; + } + } + if (nonaccess && !force && !move) { + if (sb == null) { + sb = new StringBuilder(); + sb.append('['); + sb.append(ns); + sb.append("] contains "); + } else { + sb.append(", "); + } + sb.append("permissions"); + } + } + + Result> rrdc = q.roleDAO.readNS(trans, ns); + if (rrdc.isOKhasData()) { + // Since there are now NS roles, we have to count NON-NS roles. + // FYI, if we delete th)em now, and the NS is not deleted, it is in + // an inconsistent state. + int count = rrdc.value.size(); + for (RoleDAO.Data rdd : rrdc.value) { + if ("admin".equals(rdd.name) || "owner".equals(rdd.name)) { + --count; + } + } + if (count > 0 && !force && !move) { + if (sb == null) { + sb = new StringBuilder(); + sb.append('['); + sb.append(ns); + sb.append("] contains "); + } else { + sb.append(", "); + } + sb.append("roles"); + } + } + + // 2c) Deny if dependencies exist that would be moved to root level + // parent is root level parent here. Need to find closest parent ns that + // exists + if (sb != null) { + if (!force && !move) { + sb.append(".\n Delete dependencies and try again. Note: using \"force=true\" will delete all. \"force=move\" will delete Creds, but move Roles and Perms to parent."); + return Result.err(Status.ERR_DependencyExists, sb.toString()); + } + + if (move && (parent == null || parent.type == NsType.COMPANY.type)) { + return Result + .err(Status.ERR_DependencyExists, + "Cannot move users, roles or permissions to [%s].\nDelete dependencies and try again", + parent.name); + } + } else if (move && parent != null) { + sb = new StringBuilder(); + // 3) Change any roles with children matching this NS, and + moveRoles(trans, parent, sb, rrdc); + // 4) Change any Perms with children matching this NS, and + movePerms(trans, parent, sb, rpdc); + } + + if (sb != null && sb.length() > 0) { + return Result.err(Status.ERR_DependencyExists, sb.toString()); + } + + if (er.hasErr()) { + if (trans.debug().isLoggable()) { + trans.debug().log(er.toString()); + } + return Result.err(Status.ERR_DependencyExists, + "Namespace members cannot be deleted for %s", ns); + } + + // 5) OK... good to go for NS Deletion... + if (!rpdc.isEmpty()) { + for (PermDAO.Data perm : rpdc.value) { + deletePerm(trans, perm, true, true); + } + } + if (!rrdc.isEmpty()) { + for (RoleDAO.Data role : rrdc.value) { + deleteRole(trans, role, true, true); + } + } + + return q.nsDAO.delete(trans, nsd, false); + } + + public Result> getOwners(AuthzTrans trans, String ns, + boolean includeExpired) { + return getUsersByRole(trans, ns + Question.DOT_OWNER, includeExpired); + } + + private Result mayAddOwner(AuthzTrans trans, String ns, String id) { + Result rq = q.deriveNs(trans, ns); + if (rq.notOK()) { + return Result.err(rq); + } + + rq = q.mayUser(trans, trans.user(), rq.value, Access.write); + if (rq.notOK()) { + return Result.err(rq); + } + + Identity user; + Organization org = trans.org(); + try { + if ((user = org.getIdentity(trans, id)) == null) { + return Result.err(Status.ERR_Policy, + "%s reports that this is not a valid credential", + org.getName()); + } + String reason; + if ((reason=user.mayOwn())==null) { + return Result.ok(); + } else { + if (org.isTestEnv()) { + String reason2; + if((reason2 = org.validate(trans, Policy.AS_RESPONSIBLE, new CassExecutor(trans, this), id))==null) { + return Result.ok(); + } else { + trans.debug().log(reason2); + } + } + return Result.err(Status.ERR_Policy,CANNOT_BE_THE_OWNER_OF_A_NAMESPACE,user.fullName(),user.id(),ns, reason); + } + } catch (Exception e) { + return Result.err(e); + } + } + + private Result mayAddAdmin(AuthzTrans trans, String ns, String id) { + // Does NS Exist? + Result r = checkValidID(trans, new Date(), id); + if (r.notOK()) { + return r; + } + // Is id able to be an Admin + Result rq = q.deriveNs(trans, ns); + if (rq.notOK()) { + return Result.err(rq); + } + + rq = q.mayUser(trans, trans.user(), rq.value, Access.write); + if (rq.notOK()) { + Result> ruinr = q.userRoleDAO.readUserInRole(trans, trans.user(),ns+".owner"); + if(!(ruinr.isOKhasData() && ruinr.value.get(0).expires.after(new Date()))) { + return Result.err(rq); + } + } + return r; + } + + private Result checkValidID(AuthzTrans trans, Date now, String user) { + Organization org = trans.org(); + if (user.endsWith(org.getRealm())) { + try { + if (org.getIdentity(trans, user) == null) { + return Result.err(Status.ERR_Denied, + "%s reports that %s is a faulty ID", org.getName(), + user); + } + return Result.ok(); + } catch (Exception e) { + return Result.err(Result.ERR_Security, + "%s is not a valid %s Credential", user, org.getName()); + } + //TODO find out how to make sure good ALTERNATE OAUTH DOMAIN USER +// } else if(user.endsWith(ALTERNATE OAUTH DOMAIN)) { +// return Result.ok(); + } else { + Result> cdr = q.credDAO.readID(trans, user); + if (cdr.notOKorIsEmpty()) { + return Result.err(Status.ERR_Security, + "%s is not a valid AAF Credential", user); + } + + for (CredDAO.Data cd : cdr.value) { + if (cd.expires.after(now)) { + return Result.ok(); + } + } + } + return Result.err(Result.ERR_Security, "%s has expired", user); + } + + public Result delOwner(AuthzTrans trans, String ns, String id) { + Result rq = q.deriveNs(trans, ns); + if (rq.notOK()) { + return Result.err(rq); + } + + rq = q.mayUser(trans, trans.user(), rq.value, Access.write); + if (rq.notOK()) { + return Result.err(rq); + } + + return delUserRole(trans, id, ns,Question.OWNER); + } + + public Result> getAdmins(AuthzTrans trans, String ns, boolean includeExpired) { + return getUsersByRole(trans, ns + Question.DOT_ADMIN, includeExpired); + } + + public Result delAdmin(AuthzTrans trans, String ns, String id) { + Result rq = q.deriveNs(trans, ns); + if (rq.notOK()) { + return Result.err(rq); + } + + rq = q.mayUser(trans, trans.user(), rq.value, Access.write); + if (rq.notOK()) { + // Even though not a "writer", Owners still determine who gets to be an Admin + Result> ruinr = q.userRoleDAO.readUserInRole(trans, trans.user(),ns+".owner"); + if(!(ruinr.isOKhasData() && ruinr.value.get(0).expires.after(new Date()))) { + return Result.err(rq); + } + } + + return delUserRole(trans, id, ns, Question.ADMIN); + } + + /** + * Helper function that moves permissions from a namespace being deleted to + * its parent namespace + * + * @param trans + * @param parent + * @param sb + * @param rpdc + * - list of permissions in namespace being deleted + */ + private void movePerms(AuthzTrans trans, NsDAO.Data parent, + StringBuilder sb, Result> rpdc) { + + Result rv; + Result pd; + + if (rpdc.isOKhasData()) { + for (PermDAO.Data pdd : rpdc.value) { + String delP2 = pdd.type; + if ("access".equals(delP2)) { + continue; + } + // Remove old Perm from Roles, save them off + List lrdd = new ArrayList(); + + for(String rl : pdd.roles(false)) { + Result rrdd = RoleDAO.Data.decode(trans,q,rl); + if(rrdd.isOKhasData()) { + RoleDAO.Data rdd = rrdd.value; + lrdd.add(rdd); + q.roleDAO.delPerm(trans, rdd, pdd); + } else{ + trans.error().log(rrdd.errorString()); + } + } + + // Save off Old keys + String delP1 = pdd.ns; + NsSplit nss = new NsSplit(parent, pdd.fullType()); + pdd.ns = nss.ns; + pdd.type = nss.name; + // Use direct Create/Delete, because switching namespaces + if ((pd = q.permDAO.create(trans, pdd)).isOK()) { + // Put Role back into Perm, with correct info + for(RoleDAO.Data rdd : lrdd) { + q.roleDAO.addPerm(trans, rdd, pdd); + } + + pdd.ns = delP1; + pdd.type = delP2; + if ((rv = q.permDAO.delete(trans, pdd, false)).notOK()) { + sb.append(rv.details); + sb.append('\n'); + // } else { + // Need to invalidate directly, because we're switching + // places in NS, not normal cache behavior + // q.permDAO.invalidate(trans,pdd); + } + } else { + sb.append(pd.details); + sb.append('\n'); + } + } + } + } + + /** + * Helper function that moves roles from a namespace being deleted to its + * parent namespace + * + * @param trans + * @param parent + * @param sb + * @param rrdc + * - list of roles in namespace being deleted + */ + private void moveRoles(AuthzTrans trans, NsDAO.Data parent, + StringBuilder sb, Result> rrdc) { + + Result rv; + Result rd; + + if (rrdc.isOKhasData()) { + for (RoleDAO.Data rdd : rrdc.value) { + String delP2 = rdd.name; + if ("admin".equals(delP2) || "owner".equals(delP2)) { + continue; + } + // Remove old Role from Perms, save them off + List lpdd = new ArrayList(); + for(String p : rdd.perms(false)) { + Result rpdd = PermDAO.Data.decode(trans,q,p); + if(rpdd.isOKhasData()) { + PermDAO.Data pdd = rpdd.value; + lpdd.add(pdd); + q.permDAO.delRole(trans, pdd, rdd); + } else{ + trans.error().log(rpdd.errorString()); + } + } + + // Save off Old keys + String delP1 = rdd.ns; + + NsSplit nss = new NsSplit(parent, rdd.fullName()); + rdd.ns = nss.ns; + rdd.name = nss.name; + // Use direct Create/Delete, because switching namespaces + if ((rd = q.roleDAO.create(trans, rdd)).isOK()) { + // Put Role back into Perm, with correct info + for(PermDAO.Data pdd : lpdd) { + q.permDAO.addRole(trans, pdd, rdd); + } + + rdd.ns = delP1; + rdd.name = delP2; + if ((rv = q.roleDAO.delete(trans, rdd, true)).notOK()) { + sb.append(rv.details); + sb.append('\n'); + // } else { + // Need to invalidate directly, because we're switching + // places in NS, not normal cache behavior + // q.roleDAO.invalidate(trans,rdd); + } + } else { + sb.append(rd.details); + sb.append('\n'); + } + } + } + } + + /** + * Create Permission (and any missing Permission between this and Parent) if + * we have permission + * + * Pass in the desired Management Permission for this Permission + * + * If Force is set, then Roles listed will be created, if allowed, + * pre-granted. + */ + public Result createPerm(AuthzTrans trans, PermDAO.Data perm, boolean fromApproval) { + String user = trans.user(); + // Next, see if User is allowed to Manage Parent Permission + + Result rnsd; + if (!fromApproval) { + rnsd = q.mayUser(trans, user, perm, Access.write); + if (rnsd.notOK()) { + return Result.err(rnsd); + } + } else { + rnsd = q.deriveNs(trans, perm.ns); + } + + // Does Child exist? + if (!trans.requested(REQD_TYPE.force)) { + if (q.permDAO.read(trans, perm).isOKhasData()) { + return Result.err(Status.ERR_ConflictAlreadyExists, + "Permission [%s.%s|%s|%s] already exists.", perm.ns, + perm.type, perm.instance, perm.action); + } + } + + // Attempt to add perms to roles, creating as possible + Set roles; + String pstring = perm.encode(); + + // For each Role + for (String role : roles = perm.roles(true)) { + Result rdd = RoleDAO.Data.decode(trans,q,role); + if(rdd.isOKhasData()) { + RoleDAO.Data rd = rdd.value; + if (!fromApproval) { + // May User write to the Role in question. + Result rns = q.mayUser(trans, user, rd, + Access.write); + if (rns.notOK()) { + // Remove the role from Add, because + roles.remove(role); // Don't allow adding + trans.warn() + .log("User [%s] does not have permission to relate Permissions to Role [%s]", + user, role); + } + } + + Result> rlrd; + if ((rlrd = q.roleDAO.read(trans, rd)).notOKorIsEmpty()) { + rd.perms(true).add(pstring); + if (q.roleDAO.create(trans, rd).notOK()) { + roles.remove(role); // Role doesn't exist, and can't be + // created + } + } else { + rd = rlrd.value.get(0); + if (!rd.perms.contains(pstring)) { + q.roleDAO.addPerm(trans, rd, perm); + } + } + } + } + + Result pdr = q.permDAO.create(trans, perm); + if (pdr.isOK()) { + return Result.ok(); + } else { + return Result.err(pdr); + } + } + + public Result deletePerm(final AuthzTrans trans, final PermDAO.Data perm, boolean force, boolean fromApproval) { + String user = trans.user(); + + // Next, see if User is allowed to Manage Permission + Result rnsd; + if (!fromApproval) { + rnsd = q.mayUser(trans, user, perm, Access.write); + if (rnsd.notOK()) { + return Result.err(rnsd); + } + } + // Does Perm exist? + Result> pdr = q.permDAO.read(trans, perm); + if (pdr.notOKorIsEmpty()) { + return Result.err(Status.ERR_PermissionNotFound,"Permission [%s.%s|%s|%s] does not exist.", + perm.ns,perm.type, perm.instance, perm.action); + } + // Get perm, but with rest of data. + PermDAO.Data fullperm = pdr.value.get(0); + + // Attached to any Roles? + if (fullperm.roles != null) { + if (force) { + for (String role : fullperm.roles) { + Result rv = null; + Result rrdd = RoleDAO.Data.decode(trans, q, role); + if(rrdd.isOKhasData()) { + trans.debug().log("Removing", role, "from", fullperm, "on Perm Delete"); + if ((rv = q.roleDAO.delPerm(trans, rrdd.value, fullperm)).notOK()) { + if (rv.notOK()) { + trans.error().log("Error removing Role during delFromPermRole: ", + trans.getUserPrincipal(), + rv.errorString()); + } + } + } else { + return Result.err(rrdd); + } + } + } else if (!fullperm.roles.isEmpty()) { + return Result + .err(Status.ERR_DependencyExists, + "Permission [%s.%s|%s|%s] cannot be deleted as it is attached to 1 or more roles.", + fullperm.ns, fullperm.type, fullperm.instance, fullperm.action); + } + } + + return q.permDAO.delete(trans, fullperm, false); + } + + public Result deleteRole(final AuthzTrans trans, final RoleDAO.Data role, boolean force, boolean fromApproval) { + String user = trans.user(); + + // Next, see if User is allowed to Manage Role + Result rnsd; + if (!fromApproval) { + rnsd = q.mayUser(trans, user, role, Access.write); + if (rnsd.notOK()) { + return Result.err(rnsd); + } + } + + // Are there any Users Attached to Role? + Result> urdr = q.userRoleDAO.readByRole(trans,role.fullName()); + if (force) { + if (urdr.isOKhasData()) { + for (UserRoleDAO.Data urd : urdr.value) { + q.userRoleDAO.delete(trans, urd, false); + } + } + } else if (urdr.isOKhasData()) { + return Result.err(Status.ERR_DependencyExists, + "Role [%s.%s] cannot be deleted as it is used by 1 or more Users.", + role.ns, role.name); + } + + // Does Role exist? + Result> rdr = q.roleDAO.read(trans, role); + if (rdr.notOKorIsEmpty()) { + return Result.err(Status.ERR_RoleNotFound, + "Role [%s.%s] does not exist", role.ns, role.name); + } + RoleDAO.Data fullrole = rdr.value.get(0); // full key search + + // Remove Self from Permissions... always, force or not. Force only applies to Dependencies (Users) + if (fullrole.perms != null) { + for (String perm : fullrole.perms(false)) { + Result rpd = PermDAO.Data.decode(trans,q,perm); + if (rpd.isOK()) { + trans.debug().log("Removing", perm, "from", fullrole,"on Role Delete"); + + Result r = q.permDAO.delRole(trans, rpd.value, fullrole); + if (r.notOK()) { + trans.error().log("ERR_FDR1 unable to remove",fullrole,"from",perm,':',r.status,'-',r.details); + } + } else { + trans.error().log("ERR_FDR2 Could not remove",perm,"from",fullrole); + } + } + } + return q.roleDAO.delete(trans, fullrole, false); + } + + /** + * Only owner of Permission may add to Role + * + * If force set, however, Role will be created before Grant, if User is + * allowed to create. + * + * @param trans + * @param role + * @param pd + * @return + */ + public Result addPermToRole(AuthzTrans trans, RoleDAO.Data role,PermDAO.Data pd, boolean fromApproval) { + String user = trans.user(); + + if (!fromApproval) { + Result rRoleCo = q.deriveFirstNsForType(trans, role.ns, NsType.COMPANY); + if(rRoleCo.notOK()) { + return Result.err(rRoleCo); + } + Result rPermCo = q.deriveFirstNsForType(trans, pd.ns, NsType.COMPANY); + if(rPermCo.notOK()) { + return Result.err(rPermCo); + } + + // Not from same company + if(!rRoleCo.value.name.equals(rPermCo.value.name)) { + Result r; + // Only grant if User ALSO has Write ability in Other Company + if((r = q.mayUser(trans, user, role, Access.write)).notOK()) { + return Result.err(r); + } + } + + + // Must be Perm Admin, or Granted Special Permission + Result ucp = q.mayUser(trans, user, pd, Access.write); + if (ucp.notOK()) { + // Don't allow CLI potential Grantees to change their own AAF + // Perms, + if ((ROOT_NS.equals(pd.ns) && Question.NS.equals(pd.type)) + || !q.isGranted(trans, trans.user(),ROOT_NS,Question.PERM, rPermCo.value.name, "grant")) { + // Not otherwise granted + // TODO Needed? + return Result.err(ucp); + } + // Final Check... Don't allow Grantees to add to Roles they are + // part of + Result> rlurd = q.userRoleDAO + .readByUser(trans, trans.user()); + if (rlurd.isOK()) { + for (UserRoleDAO.Data ur : rlurd.value) { + if (role.ns.equals(ur.ns) && role.name.equals(ur.rname)) { + return Result.err(ucp); + } + } + } + } + } + + Result> rlpd = q.permDAO.read(trans, pd); + if (rlpd.notOKorIsEmpty()) { + return Result.err(Status.ERR_PermissionNotFound, + "Permission must exist to add to Role"); + } + + Result> rlrd = q.roleDAO.read(trans, role); // Already + // Checked + // for + // can + // change + // Role + Result rv; + + if (rlrd.notOKorIsEmpty()) { + if (trans.requested(REQD_TYPE.force)) { + Result ucr = q.mayUser(trans, user, role, + Access.write); + if (ucr.notOK()) { + return Result + .err(Status.ERR_Denied, + "Role [%s.%s] does not exist. User [%s] cannot create.", + role.ns, role.name, user); + } + + role.perms(true).add(pd.encode()); + Result rdd = q.roleDAO.create(trans, role); + if (rdd.isOK()) { + rv = Result.ok(); + } else { + rv = Result.err(rdd); + } + } else { + return Result.err(Status.ERR_RoleNotFound, + "Role [%s.%s] does not exist.", role.ns, role.name); + } + } else { + role = rlrd.value.get(0); + if (role.perms(false).contains(pd.encode())) { + return Result.err(Status.ERR_ConflictAlreadyExists, + "Permission [%s.%s] is already a member of role [%s,%s]", + pd.ns, pd.type, role.ns, role.name); + } + role.perms(true).add(pd.encode()); // this is added for Caching + // access purposes... doesn't + // affect addPerm + rv = q.roleDAO.addPerm(trans, role, pd); + } + if (rv.status == Status.OK) { + return q.permDAO.addRole(trans, pd, role); + // exploring how to add information message to successful http + // request + } + return rv; + } + + /** + * Either Owner of Role or Permission may delete from Role + * + * @param trans + * @param role + * @param pd + * @return + */ + public Result delPermFromRole(AuthzTrans trans, RoleDAO.Data role,PermDAO.Data pd, boolean fromApproval) { + String user = trans.user(); + if (!fromApproval) { + Result ucr = q.mayUser(trans, user, role, Access.write); + Result ucp = q.mayUser(trans, user, pd, Access.write); + + // If Can't change either Role or Perm, then deny + if (ucr.notOK() && ucp.notOK()) { + return Result.err(Status.ERR_Denied, + "User [" + trans.user() + + "] does not have permission to delete [" + + pd.encode() + "] from Role [" + + role.fullName() + ']'); + } + } + + Result> rlr = q.roleDAO.read(trans, role); + if (rlr.notOKorIsEmpty()) { + // If Bad Data, clean out + Result> rlp = q.permDAO.read(trans, pd); + if (rlp.isOKhasData()) { + for (PermDAO.Data pv : rlp.value) { + q.permDAO.delRole(trans, pv, role); + } + } + return Result.err(rlr); + } + String perm1 = pd.encode(); + boolean notFound; + if (trans.requested(REQD_TYPE.force)) { + notFound = false; + } else { // only check if force not set. + notFound = true; + for (RoleDAO.Data r : rlr.value) { + if (r.perms != null) { + for (String perm : r.perms) { + if (perm1.equals(perm)) { + notFound = false; + break; + } + } + if(!notFound) { + break; + } + } + } + } + if (notFound) { // Need to check both, in case of corruption + return Result.err(Status.ERR_PermissionNotFound, + "Permission [%s.%s|%s|%s] not associated with any Role", + pd.ns,pd.type,pd.instance,pd.action); + } + + // Read Perm for full data + Result> rlp = q.permDAO.read(trans, pd); + Result rv = null; + if (rlp.isOKhasData()) { + for (PermDAO.Data pv : rlp.value) { + if ((rv = q.permDAO.delRole(trans, pv, role)).isOK()) { + if ((rv = q.roleDAO.delPerm(trans, role, pv)).notOK()) { + trans.error().log( + "Error removing Perm during delFromPermRole:", + trans.getUserPrincipal(), rv.errorString()); + } + } else { + trans.error().log( + "Error removing Role during delFromPermRole:", + trans.getUserPrincipal(), rv.errorString()); + } + } + } else { + rv = q.roleDAO.delPerm(trans, role, pd); + if (rv.notOK()) { + trans.error().log("Error removing Role during delFromPermRole", + rv.errorString()); + } + } + return rv == null ? Result.ok() : rv; + } + + public Result delPermFromRole(AuthzTrans trans, String role,PermDAO.Data pd) { + Result nss = q.deriveNsSplit(trans, role); + if (nss.notOK()) { + return Result.err(nss); + } + RoleDAO.Data rd = new RoleDAO.Data(); + rd.ns = nss.value.ns; + rd.name = nss.value.name; + return delPermFromRole(trans, rd, pd, false); + } + + /** + * Add a User to Role + * + * 1) Role must exist 2) User must be a known Credential (i.e. mechID ok if + * Credential) or known Organizational User + * + * @param trans + * @param org + * @param urData + * @return + * @throws DAOException + */ + public Result addUserRole(AuthzTrans trans,UserRoleDAO.Data urData) { + Result rv; + if(Question.ADMIN.equals(urData.rname)) { + rv = mayAddAdmin(trans, urData.ns, urData.user); + } else if(Question.OWNER.equals(urData.rname)) { + rv = mayAddOwner(trans, urData.ns, urData.user); + } else { + rv = checkValidID(trans, new Date(), urData.user); + } + if(rv.notOK()) { + return rv; + } + + // Check if record exists + if (q.userRoleDAO.read(trans, urData).isOKhasData()) { + return Result.err(Status.ERR_ConflictAlreadyExists, + "User Role exists"); + } + if (q.roleDAO.read(trans, urData.ns, urData.rname).notOKorIsEmpty()) { + return Result.err(Status.ERR_RoleNotFound, + "Role [%s.%s] does not exist", urData.ns, urData.rname); + } + + urData.expires = trans.org().expiration(null, Expiration.UserInRole, urData.user).getTime(); + + + Result udr = q.userRoleDAO.create(trans, urData); + switch (udr.status) { + case OK: + return Result.ok(); + default: + return Result.err(udr); + } + } + + public Result addUserRole(AuthzTrans trans, String user, String ns, String rname) { + try { + if(trans.org().getIdentity(trans, user)==null) { + return Result.err(Result.ERR_BadData,user+" is an Invalid Identity for " + trans.org().getName()); + } + } catch (OrganizationException e) { + return Result.err(e); + } + UserRoleDAO.Data urdd = new UserRoleDAO.Data(); + urdd.ns = ns; + urdd.role(ns, rname); + urdd.user = user; + return addUserRole(trans,urdd); + } + + /** + * Extend User Role. + * + * extend the Expiration data, according to Organization rules. + * + * @param trans + * @param org + * @param urData + * @return + */ + public Result extendUserRole(AuthzTrans trans, UserRoleDAO.Data urData, boolean checkForExist) { + // Check if record still exists + if (checkForExist && q.userRoleDAO.read(trans, urData).notOKorIsEmpty()) { + return Result.err(Status.ERR_UserRoleNotFound, + "User Role does not exist"); + } + + if (q.roleDAO.read(trans, urData.ns, urData.rname).notOKorIsEmpty()) { + return Result.err(Status.ERR_RoleNotFound, + "Role [%s.%s] does not exist", urData.ns,urData.rname); + } + // Special case for "Admin" roles. Issue brought forward with Prod + // problem 9/26 + Date now = new Date(); + GregorianCalendar gc = new GregorianCalendar(); + gc.setTime(now.after(urData.expires)?now:urData.expires); + urData.expires = trans.org().expiration(gc, Expiration.UserInRole).getTime(); // get + // Full + // time + // starting + // today + return q.userRoleDAO.update(trans, urData); + } + + // //////////////////////////////////////////////////// + // Special User Role Functions + // These exist, because User Roles have Expiration dates, which must be + // accounted for + // Also, as of July, 2015, Namespace Owners and Admins are now regular User + // Roles + // //////////////////////////////////////////////////// + public Result> getUsersByRole(AuthzTrans trans, String role, boolean includeExpired) { + Result> rurdd = q.userRoleDAO.readByRole(trans,role); + if (rurdd.notOK()) { + return Result.err(rurdd); + } + Date now = new Date(); + List list = rurdd.value; + List rv = new ArrayList(list.size()); // presize + for (UserRoleDAO.Data urdd : rurdd.value) { + if (includeExpired || urdd.expires.after(now)) { + rv.add(urdd.user); + } + } + return Result.ok(rv); + } + + public Result delUserRole(AuthzTrans trans, String user, String ns, String rname) { + UserRoleDAO.Data urdd = new UserRoleDAO.Data(); + urdd.user = user; + urdd.role(ns,rname); + Result> r = q.userRoleDAO.read(trans, urdd); + if (r.status == 404 || r.isEmpty()) { + return Result.err(Status.ERR_UserRoleNotFound, + "UserRole [%s] [%s.%s]", user, ns, rname); + } + if (r.notOK()) { + return Result.err(r); + } + + return q.userRoleDAO.delete(trans, urdd, false); + } + + public Result createFuture(AuthzTrans trans, FutureDAO.Data data, String id, String user, + NsDAO.Data nsd, FUTURE_OP op) { + StringBuilder sb = new StringBuilder(); + try { + Organization org = trans.org(); + // For Reapproval, only check Owners.. Do Supervisors, etc, separately + List approvers = op.equals(FUTURE_OP.A)?NO_ADDL_APPROVE:org.getApprovers(trans, user); + List owners = new ArrayList(); + if (nsd != null) { + Result> rrbr = q.userRoleDAO + .readByRole(trans, nsd.name + Question.DOT_OWNER); + if (rrbr.isOKhasData()) { + for(UserRoleDAO.Data urd : rrbr.value) { + Identity owner = org.getIdentity(trans, urd.user); + if(owner==null) { + return Result.err(Result.ERR_NotFound,urd.user + " is not a Valid Owner of " + nsd.name); + } else { + owners.add(owner); + } + } + } + } + + if(owners.isEmpty()) { + return Result.err(Result.ERR_NotFound,"No Owners found for " + nsd.name); + } + + // Create Future Object + + Result fr = q.futureDAO.create(trans, data, id); + if (fr.isOK()) { + sb.append("Created Future: "); + sb.append(data.id); + // User Future ID as ticket for Approvals + final UUID ticket = fr.value.id; + sb.append(", Approvals: "); + Boolean first[] = new Boolean[]{true}; + if(op!=FUTURE_OP.A) { + for (Identity u : approvers) { + Result r = addIdentity(trans,sb,first,user,data.memo,op,u,ticket,org.getApproverType()); + if(r.notOK()) { + return Result.err(r); + } + } + } + for (Identity u : owners) { + Result r = addIdentity(trans,sb,first,user,data.memo,op,u,ticket,"owner"); + if(r.notOK()) { + return Result.err(r); + } + } + } + } catch (Exception e) { + return Result.err(e); + } + + return Result.ok(sb.toString()); + } + + /* + * This interface is to allow performFutureOps with either Realtime Data, or Batched lookups (See Expiring) + */ + public interface Lookup { + T get(AuthzTrans trans, Object ... keys); + } + + public Lookup urDBLookup = new Lookup() { + @Override + public UserRoleDAO.Data get(AuthzTrans trans, Object ... keys) { + Result> r = q.userRoleDAO.read(trans, keys); + if(r.isOKhasData()) { + return r.value.get(0); + } else { + return null; + } + } + }; + + /** + * Note: if "allApprovals for Ticket is null, it will be looked up. + * if "fdd" is null, it will be looked up, but + * + * They can be passed for performance reasons. + * + * @param trans + * @param cd + * @param allApprovalsForTicket + * @return + */ + public Result performFutureOp(final AuthzTrans trans, FUTURE_OP fop, FutureDAO.Data curr, Lookup> la, Lookup lur) { + // Pre-Evaluate if ReApproval is already done. + UserRoleDAO.Data urdd = null; + if(fop.equals(FUTURE_OP.A) && curr.target.equals(FOP_USER_ROLE) && curr.construct!=null) { + try { + // Get Expected UserRole from Future + urdd = new UserRoleDAO.Data(); + urdd.reconstitute(curr.construct); + // Get Current UserRole from lookup + UserRoleDAO.Data lurdd = lur.get(trans, urdd.user,urdd.role); + if(lurdd==null) { + q.futureDAO.delete(trans, curr, false); + return OP_STATUS.RL; + } else { + if(curr.expires.compareTo(lurdd.expires)<0) { + q.futureDAO.delete(trans, curr, false); + return OP_STATUS.RL; + } + } + } catch (IOException e) { + return Result.err(Result.ERR_BadData,"Cannot reconstitute %1",curr.memo); + } + } + + boolean aDenial = false; + int cntSuper=0, appSuper=0,cntOwner=0, appOwner=0; + for(ApprovalDAO.Data add : la.get(trans)) { + switch(add.status) { + case "approved": + if("owner".equals(add.type)) { + ++cntOwner; + ++appOwner; + } else if("supervisor".equals(add.type)) { + ++cntSuper; + ++appSuper; + } + break; + case "pending": + if("owner".equals(add.type)) { + ++cntOwner; + } else if("supervisor".equals(add.type)) { + ++cntSuper; + } + break; + case "denied": + aDenial=true; + break; + } + } + + Result ros=null; + if(aDenial) { + // Note: Denial will be Audit-logged. +// for (ApprovalDAO.Data ad : allApprovalsForTicket.value) { +// q.approvalDAO.delete(trans, ad, false); +// } + ros = OP_STATUS.RD; + if(q.futureDAO.delete(trans, curr, false).notOK()) { + trans.info().printf("Future %s could not be deleted", curr.id.toString()); + } else { + if (FOP_USER_ROLE.equalsIgnoreCase(curr.target)) { + // A Denial means we must remove UserRole + if(fop.equals(FUTURE_OP.U) || fop.equals(FUTURE_OP.A)) { + UserRoleDAO.Data data = new UserRoleDAO.Data(); + try { + data.reconstitute(curr.construct); + } catch (IOException e) { + trans.error().log("Cannot reconstitue",curr.memo); + } + ros = set(OP_STATUS.RD,delUserRole(trans, data.user, data.ns, data.rname)); + } + } + } + } + + // Decision: If not Denied, and at least owner, if exists, and at least one Super, if exists + boolean goDecision = (cntOwner>0?appOwner>0:true) && (cntSuper>0?appSuper>0:true); + + if(goDecision) { + // should check if any other pendings before performing + // actions + try { + if (FOP_ROLE.equalsIgnoreCase(curr.target)) { + RoleDAO.Data data = new RoleDAO.Data(); + data.reconstitute(curr.construct); + switch(fop) { + case C: + ros = set(OP_STATUS.RE,q.roleDAO.dao().create(trans, data)); + break; + case D: + ros = set(OP_STATUS.RE,deleteRole(trans, data, true, true)); + break; + default: + } + } else if (FOP_PERM.equalsIgnoreCase(curr.target)) { + PermDAO.Data pdd = new PermDAO.Data(); + pdd.reconstitute(curr.construct); + Set roles; + Result rrdd; + switch(fop) { + case C: + ros = set(OP_STATUS.RE,createPerm(trans, pdd, true)); + break; + case D: + ros = set(OP_STATUS.RE,deletePerm(trans, pdd, true, true)); + break; + case G: + roles = pdd.roles(true); + for (String roleStr : roles) { + rrdd = RoleDAO.Data.decode(trans, q, roleStr); + if (rrdd.isOKhasData()) { + ros = set(OP_STATUS.RE,addPermToRole(trans, rrdd.value, pdd, true)); + } else { + trans.error().log(rrdd.errorString()); + } + } + break; + case UG: + roles = pdd.roles(true); + for (String roleStr : roles) { + rrdd = RoleDAO.Data.decode(trans, q, roleStr); + if (rrdd.isOKhasData()) { + ros = set(OP_STATUS.RE,delPermFromRole(trans, rrdd.value, pdd, true)); + } else { + trans.error().log(rrdd.errorString()); + } + } + break; + default: + } + } else if (FOP_USER_ROLE.equalsIgnoreCase(curr.target)) { + if(urdd==null) { + urdd = new UserRoleDAO.Data(); + urdd.reconstitute(curr.construct); + } + // if I am the last to approve, create user role + switch(fop) { + case C: + ros = set(OP_STATUS.RE,addUserRole(trans, urdd)); + break; + case U: + case A: + ros = set(OP_STATUS.RE,extendUserRole(trans,urdd,true)); + break; + default: + } + } else if (FOP_NS.equalsIgnoreCase(curr.target)) { + Namespace namespace = new Namespace(); + namespace.reconstitute(curr.construct); + switch(fop) { + case C: + ros = set(OP_STATUS.RE,createNS(trans, namespace, true)); + break; + default: + } + } else if (FOP_DELEGATE.equalsIgnoreCase(curr.target)) { + DelegateDAO.Data data = new DelegateDAO.Data(); + data.reconstitute(curr.construct); + switch(fop) { + case C: + ros = set(OP_STATUS.RE,q.delegateDAO.create(trans, data)); + break; + case U: + ros = set(OP_STATUS.RE,q.delegateDAO.update(trans, data)); + break; + default: + } + } else if (FOP_CRED.equalsIgnoreCase(curr.target)) { + CredDAO.Data data = new CredDAO.Data(); + data.reconstitute(curr.construct); + switch(fop) { + case C: + ros = set(OP_STATUS.RE,q.credDAO.dao().create(trans, data)); + break; + default: + } + } + } catch (Throwable e) { + trans.error().log("Exception: ", e.getMessage(), + " \n occurred while performing", curr.memo, + " from Ticket ", curr.id.toString()); + } + q.futureDAO.delete(trans, curr, false); + } // end for goDecision + if(ros==null) { + //return Result.err(Status.ACC_Future, "Full Approvals not obtained: No action taken"); + ros = OP_STATUS.RP; + } + + return ros; + } + + // Convenience method for setting OPSTatus Results + private Result set(Result rs, Result orig) { + if(orig.isOK()) { + return rs; + } else { + return Result.err(orig); + } + } + + private Result addIdentity(AuthzTrans trans, StringBuilder sb, + Boolean[] first, String user, String memo, FUTURE_OP op, Identity u, UUID ticket, String type) throws OrganizationException { + ApprovalDAO.Data ad = new ApprovalDAO.Data(); + // Note ad.id is set by ApprovalDAO Create + ad.ticket = ticket; + ad.user = user; + ad.approver = u.fullID(); + ad.status = ApprovalDAO.PENDING; + ad.memo = memo; + ad.type = type; + ad.operation = op.name(); + // Note ad.updated is created in System + Result r = q.approvalDAO.create(trans,ad); + if(r.isOK()) { + if(first[0]) { + first[0] = false; + } else { + sb.append(", "); + } + sb.append(r.value.user); + sb.append(':'); + sb.append(r.value.ticket); + return r; + } else { + return Result.err(Status.ERR_ActionNotCompleted, + "Approval for %s, %s could not be created: %s", + ad.user, ad.approver, + r.details, sb.toString()); + } + } + + public Executor newExecutor(AuthzTrans trans) { + return new CassExecutor(trans, this); + } + +} diff --git a/auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/hl/PermLookup.java b/auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/hl/PermLookup.java new file mode 100644 index 00000000..615d6b36 --- /dev/null +++ b/auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/hl/PermLookup.java @@ -0,0 +1,185 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.dao.hl; + +import java.util.ArrayList; +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.TreeSet; + +import org.onap.aaf.auth.dao.cass.PermDAO; +import org.onap.aaf.auth.dao.cass.RoleDAO; +import org.onap.aaf.auth.dao.cass.Status; +import org.onap.aaf.auth.dao.cass.UserRoleDAO; +import org.onap.aaf.auth.env.AuthzTrans; +import org.onap.aaf.auth.layer.Result; + +/** + * PermLookup is a Storage class for the various pieces of looking up Permission + * during Transactions to avoid duplicate processing + * + * @author Jonathan + * + */ +// Package on purpose +class PermLookup { + private AuthzTrans trans; + private String user; + private Question q; + private Result> userRoles = null; + private Result> roles = null; + private Result> permNames = null; + private Result> perms = null; + + private PermLookup() {} + + static PermLookup get(AuthzTrans trans, Question q, String user) { + PermLookup lp=null; + Map permMap = trans.get(Question.PERMS, null); + if (permMap == null) { + trans.put(Question.PERMS, permMap = new HashMap()); + } else { + lp = permMap.get(user); + } + + if (lp == null) { + lp = new PermLookup(); + lp.trans = trans; + lp.user = user; + lp.q = q; + permMap.put(user, lp); + } + return lp; + } + + public Result> getUserRoles() { + if(userRoles==null) { + userRoles = q.userRoleDAO.readByUser(trans,user); + if(userRoles.isOKhasData()) { + List lurdd = new ArrayList(); + Date now = new Date(); + for(UserRoleDAO.Data urdd : userRoles.value) { + if(urdd.expires.after(now)) { // Remove Expired + lurdd.add(urdd); + } + } + if(lurdd.size()==0) { + return userRoles = Result.err(Status.ERR_UserNotFound, + "%s not found or not associated with any Roles: ", + user); + } else { + return userRoles = Result.ok(lurdd); + } + } else { + return userRoles; + } + } else { + return userRoles; + } + } + + public Result> getRoles() { + if(roles==null) { + Result> rur = getUserRoles(); + if(rur.isOK()) { + List lrdd = new ArrayList(); + for (UserRoleDAO.Data urdata : rur.value) { + // Gather all permissions from all Roles + if(urdata.ns==null || urdata.rname==null) { + return Result.err(Status.ERR_BadData,"DB Content Error: nulls in User Role %s %s", urdata.user,urdata.role); + } else { + Result> rlrd = q.roleDAO.read( + trans, urdata.ns, urdata.rname); + if(rlrd.isOK()) { + lrdd.addAll(rlrd.value); + } + } + } + return roles = Result.ok(lrdd); + } else { + return roles = Result.err(rur); + } + } else { + return roles; + } + } + + public Result> getPermNames() { + if(permNames==null) { + Result> rlrd = getRoles(); + if (rlrd.isOK()) { + Set pns = new TreeSet(); + for (RoleDAO.Data rdata : rlrd.value) { + pns.addAll(rdata.perms(false)); + } + return permNames = Result.ok(pns); + } else { + return permNames = Result.err(rlrd); + } + } else { + return permNames; + } + } + + public Result> getPerms(boolean lookup) { + if(perms==null) { + // Note: It should be ok for a Valid user to have no permissions - + // Jonathan 8/12/2013 + Result> rss = getPermNames(); + if(rss.isOK()) { + List lpdd = new ArrayList(); + for (String perm : rss.value) { + if(lookup) { + Result ap = PermDAO.Data.decodeToArray(trans, q, perm); + if(ap.isOK()) { + + Result> rlpd = q.permDAO.read(perm,trans,ap.value); + if (rlpd.isOKhasData()) { + for (PermDAO.Data pData : rlpd.value) { + lpdd.add(pData); + } + } + } else { + trans.error().log("In getPermsByUser, for", user, perm); + } + } else { + Result pr = PermDAO.Data.decode(trans, q, perm); + if (pr.notOK()) { + trans.error().log("In getPermsByUser, for", user, pr.errorString()); + } else { + lpdd.add(pr.value); + } + } + + } + return perms = Result.ok(lpdd); + } else { + return perms = Result.err(rss); + } + } else { + return perms; + } + } +} diff --git a/auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/hl/Question.java b/auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/hl/Question.java new file mode 100644 index 00000000..6b0bb17b --- /dev/null +++ b/auth/auth-cass/src/main/java/org/onap/aaf/auth/dao/hl/Question.java @@ -0,0 +1,1154 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.dao.hl; + +import java.io.IOException; +import java.nio.ByteBuffer; +import java.security.NoSuchAlgorithmException; +import java.security.SecureRandom; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.Date; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Random; +import java.util.Set; +import java.util.TreeSet; + +import org.onap.aaf.auth.common.Define; +import org.onap.aaf.auth.dao.AbsCassDAO; +import org.onap.aaf.auth.dao.CachedDAO; +import org.onap.aaf.auth.dao.DAOException; +import org.onap.aaf.auth.dao.cached.CachedCertDAO; +import org.onap.aaf.auth.dao.cached.CachedCredDAO; +import org.onap.aaf.auth.dao.cached.CachedNSDAO; +import org.onap.aaf.auth.dao.cached.CachedPermDAO; +import org.onap.aaf.auth.dao.cached.CachedRoleDAO; +import org.onap.aaf.auth.dao.cached.CachedUserRoleDAO; +import org.onap.aaf.auth.dao.cass.ApprovalDAO; +import org.onap.aaf.auth.dao.cass.CacheInfoDAO; +import org.onap.aaf.auth.dao.cass.CertDAO; +import org.onap.aaf.auth.dao.cass.CredDAO; +import org.onap.aaf.auth.dao.cass.DelegateDAO; +import org.onap.aaf.auth.dao.cass.FutureDAO; +import org.onap.aaf.auth.dao.cass.HistoryDAO; +import org.onap.aaf.auth.dao.cass.LocateDAO; +import org.onap.aaf.auth.dao.cass.NsDAO; +import org.onap.aaf.auth.dao.cass.NsSplit; +import org.onap.aaf.auth.dao.cass.NsType; +import org.onap.aaf.auth.dao.cass.PermDAO; +import org.onap.aaf.auth.dao.cass.RoleDAO; +import org.onap.aaf.auth.dao.cass.Status; +import org.onap.aaf.auth.dao.cass.UserRoleDAO; +import org.onap.aaf.auth.dao.cass.CredDAO.Data; +import org.onap.aaf.auth.env.AuthzTrans; +import org.onap.aaf.auth.env.AuthzTransFilter; +import org.onap.aaf.auth.env.AuthzTrans.REQD_TYPE; +import org.onap.aaf.auth.layer.Result; +import org.onap.aaf.auth.org.Organization; +import org.onap.aaf.cadi.Hash; +import org.onap.aaf.cadi.aaf.PermEval; +import org.onap.aaf.cadi.config.Config; +import org.onap.aaf.misc.env.APIException; +import org.onap.aaf.misc.env.Env; +import org.onap.aaf.misc.env.Slot; +import org.onap.aaf.misc.env.TimeTaken; +import org.onap.aaf.misc.env.util.Chrono; + +import com.datastax.driver.core.Cluster; + +/** + * Question HL DAO + * + * A Data Access Combination Object which asks Security and other Questions + * + * @author Jonathan + * + */ +public class Question { + + // DON'T CHANGE FROM lower Case!!! + public static enum Type { + ns, role, perm, cred + }; + + public static final String OWNER="owner"; + public static final String ADMIN="admin"; + public static final String DOT_OWNER=".owner"; + public static final String DOT_ADMIN=".admin"; + public static final String ACCESS = "access"; + + static final String ASTERIX = "*"; + + public static enum Access { + read, write, create + }; + + public static final String READ = Access.read.name(); + public static final String WRITE = Access.write.name(); + public static final String CREATE = Access.create.name(); + + public static final String ROLE = Type.role.name(); + public static final String PERM = Type.perm.name(); + public static final String NS = Type.ns.name(); + public static final String CRED = Type.cred.name(); + private static final String DELG = "delg"; + public static final String ROOT_NS = Define.ROOT_NS(); + public static final String ATTRIB = "attrib"; + + + public static final int MAX_SCOPE = 10; + public static final int APP_SCOPE = 3; + public static final int COMPANY_SCOPE = 2; + static Slot PERMS; + + private static Set specialLog = null; + public static final Random random = new SecureRandom(); + private static long traceID = random.nextLong(); + private static Slot specialLogSlot = null; + private static Slot transIDSlot = null; + + + public final HistoryDAO historyDAO; + public final CachedNSDAO nsDAO; + public final CachedRoleDAO roleDAO; + public final CachedPermDAO permDAO; + public final CachedUserRoleDAO userRoleDAO; + public final CachedCredDAO credDAO; + public final CachedCertDAO certDAO; + public final DelegateDAO delegateDAO; + public final FutureDAO futureDAO; + public final ApprovalDAO approvalDAO; + private final CacheInfoDAO cacheInfoDAO; + public final LocateDAO locateDAO; + + public Question(AuthzTrans trans, Cluster cluster, String keyspace, boolean startClean) throws APIException, IOException { + PERMS = trans.slot("USER_PERMS"); + trans.init().log("Instantiating DAOs"); + long expiresIn = Long.parseLong(trans.getProperty(Config.AAF_USER_EXPIRES, Config.AAF_USER_EXPIRES_DEF)); + historyDAO = new HistoryDAO(trans, cluster, keyspace); + + // Deal with Cached Entries + cacheInfoDAO = new CacheInfoDAO(trans, historyDAO); + + nsDAO = new CachedNSDAO(new NsDAO(trans, historyDAO, cacheInfoDAO),cacheInfoDAO, expiresIn); + permDAO = new CachedPermDAO(new PermDAO(trans, historyDAO, cacheInfoDAO), cacheInfoDAO, expiresIn); + roleDAO = new CachedRoleDAO(new RoleDAO(trans, historyDAO, cacheInfoDAO), cacheInfoDAO, expiresIn); + userRoleDAO = new CachedUserRoleDAO(new UserRoleDAO(trans, historyDAO,cacheInfoDAO), cacheInfoDAO, expiresIn); + credDAO = new CachedCredDAO(new CredDAO(trans, historyDAO, cacheInfoDAO), cacheInfoDAO, expiresIn); + certDAO = new CachedCertDAO(new CertDAO(trans, historyDAO, cacheInfoDAO), cacheInfoDAO, expiresIn); + + locateDAO = new LocateDAO(trans,historyDAO); + futureDAO = new FutureDAO(trans, historyDAO); + delegateDAO = new DelegateDAO(trans, historyDAO); + approvalDAO = new ApprovalDAO(trans, historyDAO); + + // Only want to aggressively cleanse User related Caches... The others, + // just normal refresh + if(startClean) { + CachedDAO.startCleansing(trans.env(), credDAO, userRoleDAO); + CachedDAO.startRefresh(trans.env(), cacheInfoDAO); + } + // Set a Timer to Check Caches to send messages for Caching changes + + if(specialLogSlot==null) { + specialLogSlot = trans.slot(AuthzTransFilter.SPECIAL_LOG_SLOT); + } + + if(transIDSlot==null) { + transIDSlot = trans.slot(AuthzTransFilter.TRANS_ID_SLOT); + } + + AbsCassDAO.primePSIs(trans); + } + + + public void close(AuthzTrans trans) { + historyDAO.close(trans); + cacheInfoDAO.close(trans); + nsDAO.close(trans); + permDAO.close(trans); + roleDAO.close(trans); + userRoleDAO.close(trans); + credDAO.close(trans); + certDAO.close(trans); + delegateDAO.close(trans); + futureDAO.close(trans); + approvalDAO.close(trans); + } + + public Result permFrom(AuthzTrans trans, String type, + String instance, String action) { + Result rnd = deriveNs(trans, type); + if (rnd.isOK()) { + return Result.ok(new PermDAO.Data(new NsSplit(rnd.value, type), + instance, action)); + } else { + return Result.err(rnd); + } + } + + /** + * getPermsByUser + * + * Because this call is frequently called internally, AND because we already + * look for it in the initial Call, we cache within the Transaction + * + * @param trans + * @param user + * @return + */ + public Result> getPermsByUser(AuthzTrans trans, String user, boolean lookup) { + return PermLookup.get(trans, this, user).getPerms(lookup); + } + + public Result> getPermsByUserFromRolesFilter(AuthzTrans trans, String user, String forUser) { + PermLookup plUser = PermLookup.get(trans, this, user); + Result> plPermNames = plUser.getPermNames(); + if(plPermNames.notOK()) { + return Result.err(plPermNames); + } + + Set nss; + if(forUser.equals(user)) { + nss = null; + } else { + // Setup a TreeSet to check on Namespaces to + nss = new TreeSet(); + PermLookup fUser = PermLookup.get(trans, this, forUser); + Result> forUpn = fUser.getPermNames(); + if(forUpn.notOK()) { + return Result.err(forUpn); + } + + for(String pn : forUpn.value) { + Result decoded = PermDAO.Data.decodeToArray(trans, this, pn); + if(decoded.isOKhasData()) { + nss.add(decoded.value[0]); + } else { + trans.error().log(pn,", derived from a Role, is invalid:",decoded.errorString()); + } + } + } + + List rlpUser = new ArrayList(); + Result rpdd; + PermDAO.Data pdd; + for(String pn : plPermNames.value) { + rpdd = PermDAO.Data.decode(trans, this, pn); + if(rpdd.isOKhasData()) { + pdd=rpdd.value; + if(nss==null || nss.contains(pdd.ns)) { + rlpUser.add(pdd); + } + } else { + trans.error().log(pn,", derived from a Role, is invalid. Run Data Cleanup:",rpdd.errorString()); + } + } + return Result.ok(rlpUser); + } + + public Result> getPermsByType(AuthzTrans trans, String perm) { + Result nss = deriveNsSplit(trans, perm); + if (nss.notOK()) { + return Result.err(nss); + } + return permDAO.readByType(trans, nss.value.ns, nss.value.name); + } + + public Result> getPermsByName(AuthzTrans trans, + String type, String instance, String action) { + Result nss = deriveNsSplit(trans, type); + if (nss.notOK()) { + return Result.err(nss); + } + return permDAO.read(trans, nss.value.ns, nss.value.name, instance,action); + } + + public Result> getPermsByRole(AuthzTrans trans, String role, boolean lookup) { + Result nss = deriveNsSplit(trans, role); + if (nss.notOK()) { + return Result.err(nss); + } + + Result> rlrd = roleDAO.read(trans, nss.value.ns, + nss.value.name); + if (rlrd.notOKorIsEmpty()) { + return Result.err(rlrd); + } + // Using Set to avoid duplicates + Set permNames = new HashSet(); + if (rlrd.isOKhasData()) { + for (RoleDAO.Data drr : rlrd.value) { + permNames.addAll(drr.perms(false)); + } + } + + // Note: It should be ok for a Valid user to have no permissions - + // Jonathan 8/12/2013 + List perms = new ArrayList(); + for (String perm : permNames) { + Result pr = PermDAO.Data.decode(trans, this, perm); + if (pr.notOK()) { + return Result.err(pr); + } + + if(lookup) { + Result> rlpd = permDAO.read(trans, pr.value); + if (rlpd.isOKhasData()) { + for (PermDAO.Data pData : rlpd.value) { + perms.add(pData); + } + } + } else { + perms.add(pr.value); + } + } + + return Result.ok(perms); + } + + public Result> getRolesByName(AuthzTrans trans, + String role) { + Result nss = deriveNsSplit(trans, role); + if (nss.notOK()) { + return Result.err(nss); + } + String r = nss.value.name; + if (r.endsWith(".*")) { // do children Search + return roleDAO.readChildren(trans, nss.value.ns, + r.substring(0, r.length() - 2)); + } else if (ASTERIX.equals(r)) { + return roleDAO.readChildren(trans, nss.value.ns, ASTERIX); + } else { + return roleDAO.read(trans, nss.value.ns, r); + } + } + + /** + * Derive NS + * + * Given a Child Namespace, figure out what the best Namespace parent is. + * + * For instance, if in the NS table, the parent "com.att" exists, but not + * "org.osaaf.child" or "org.osaaf.a.b.c", then passing in either + * "org.osaaf.child" or "org.osaaf.a.b.c" will return "com.att" + * + * Uses recursive search on Cached DAO data + * + * @param trans + * @param child + * @return + */ + public Result deriveNs(AuthzTrans trans, String child) { + Result> r = nsDAO.read(trans, child); + + if (r.isOKhasData()) { + return Result.ok(r.value.get(0)); + } else { + int dot = child == null ? -1 : child.lastIndexOf('.'); + if (dot < 0) { + return Result.err(Status.ERR_NsNotFound, + "No Namespace for [%s]", child); + } else { + return deriveNs(trans, child.substring(0, dot)); + } + } + } + + public Result deriveFirstNsForType(AuthzTrans trans, String str, NsType type) { + NsDAO.Data nsd; + + for(String lookup = str;!".".equals(lookup) && lookup!=null;) { + Result> rld = nsDAO.read(trans, lookup); + if(rld.isOKhasData()) { + nsd=rld.value.get(0); + lookup = nsd.parent; + if(type.type == nsd.type) { + return Result.ok(nsd); + } + } else { + return Result.err(Status.ERR_NsNotFound,"There is no valid Company Namespace for %s",str); + } + } + return Result.err(Status.ERR_NotFound, str + " does not contain type " + type.name()); + } + + public Result deriveNsSplit(AuthzTrans trans, String child) { + Result ndd = deriveNs(trans, child); + if (ndd.isOK()) { + NsSplit nss = new NsSplit(ndd.value, child); + if (nss.isOK()) { + return Result.ok(nss); + } else { + return Result.err(Status.ERR_NsNotFound, + "Cannot split [%s] into valid namespace elements", + child); + } + } + return Result.err(ndd); + } + + /** + * Translate an ID into it's domain + * + * i.e. myid1234@aaf.att.com results in domain of com.att.aaf + * + * @param id + * @return + */ + public static String domain2ns(String id) { + int at = id.indexOf('@'); + if (at >= 0) { + String[] domain = id.substring(at + 1).split("\\."); + StringBuilder ns = new StringBuilder(id.length()); + boolean first = true; + for (int i = domain.length - 1; i >= 0; --i) { + if (first) { + first = false; + } else { + ns.append('.'); + } + ns.append(domain[i]); + } + return ns.toString(); + } else { + return ""; + } + + } + + /** + * Validate Namespace of ID@Domain + * + * Namespace is reverse order of Domain. + * + * @param trans + * @param id + * @return + */ + public Result validNSOfDomain(AuthzTrans trans, String id) { + // Take domain, reverse order, and check on NS + String ns; + if(id.indexOf('@')<0) { // it's already an ns, not an ID + ns = id; + } else { + ns = domain2ns(id); + } + if (ns.length() > 0) { + if(!trans.org().getDomain().equals(ns)) { + Result> rlnsd = nsDAO.read(trans, ns); + if (rlnsd.isOKhasData()) { + return Result.ok(rlnsd.value.get(0)); + } + } + } + return Result.err(Status.ERR_NsNotFound, + "A Namespace is not available for %s", id); + } + + public Result mayUser(AuthzTrans trans, String user,NsDAO.Data ndd, Access access) { + // .access|:role:| + String ns = ndd.name; + int last; + do { + if (isGranted(trans, user, ns, ACCESS, ":ns", access.name())) { + return Result.ok(ndd); + } + if ((last = ns.lastIndexOf('.')) >= 0) { + ns = ns.substring(0, last); + } + } while (last >= 0); + // com.att.aaf.ns|::ns| + // AAF-724 - Make consistent response for May User", and not take the + // last check... too confusing. + Result rv = mayUserVirtueOfNS(trans, user, ndd, ":" + ndd.name + ":ns", access.name()); + if (rv.isOK()) { + return rv; + } else if(rv.status==Result.ERR_Backend) { + return Result.err(rv); + } else { + return Result.err(Status.ERR_Denied, "[%s] may not %s in NS [%s]", + user, access.name(), ndd.name); + } + } + + public Result mayUser(AuthzTrans trans, String user, RoleDAO.Data rdd, Access access) { + Result rnsd = deriveNs(trans, rdd.ns); + if (rnsd.isOK()) { + return mayUser(trans, user, rnsd.value, rdd, access); + } + return rnsd; + } + + public Result mayUser(AuthzTrans trans, String user, NsDAO.Data ndd, RoleDAO.Data rdd, Access access) { + // 1) Is User in the Role? + Result> rurd = userRoleDAO.readUserInRole(trans, user, rdd.fullName()); + if (rurd.isOKhasData()) { + return Result.ok(ndd); + } + + String roleInst = ":role:" + rdd.name; + // .access|:role:| + String ns = rdd.ns; + int last; + do { + if (isGranted(trans, user, ns,ACCESS, roleInst, access.name())) { + return Result.ok(ndd); + } + if ((last = ns.lastIndexOf('.')) >= 0) { + ns = ns.substring(0, last); + } + } while (last >= 0); + + // Check if Access by Global Role perm + // com.att.aaf.ns|::role:name| + Result rnsd = mayUserVirtueOfNS(trans, user, ndd, ":" + + rdd.ns + roleInst, access.name()); + if (rnsd.isOK()) { + return rnsd; + } else if(rnsd.status==Result.ERR_Backend) { + return Result.err(rnsd); + } + + // Check if Access to Whole NS + // AAF-724 - Make consistent response for May User", and not take the + // last check... too confusing. + Result rv = mayUserVirtueOfNS(trans, user, ndd, + ":" + rdd.ns + ":ns", access.name()); + if (rv.isOK()) { + return rv; + } else if(rnsd.status==Result.ERR_Backend) { + return Result.err(rnsd); + } else { + return Result.err(Status.ERR_Denied, "[%s] may not %s Role [%s]", + user, access.name(), rdd.fullName()); + } + + } + + public Result mayUser(AuthzTrans trans, String user,PermDAO.Data pdd, Access access) { + Result rnsd = deriveNs(trans, pdd.ns); + if (rnsd.isOK()) { + return mayUser(trans, user, rnsd.value, pdd, access); + } + return rnsd; + } + + public Result mayUser(AuthzTrans trans, String user,NsDAO.Data ndd, PermDAO.Data pdd, Access access) { + if (isGranted(trans, user, pdd.ns, pdd.type, pdd.instance, pdd.action)) { + return Result.ok(ndd); + } + String permInst = ":perm:" + pdd.type + ':' + pdd.instance + ':' + pdd.action; + // .access|:role:| + String ns = ndd.name; + int last; + do { + if (isGranted(trans, user, ns, ACCESS, permInst, access.name())) { + return Result.ok(ndd); + } + if ((last = ns.lastIndexOf('.')) >= 0) { + ns = ns.substring(0, last); + } + } while (last >= 0); + + // Check if Access by NS perm + // com.att.aaf.ns|::role:name| + Result rnsd = mayUserVirtueOfNS(trans, user, ndd, ":" + pdd.ns + permInst, access.name()); + if (rnsd.isOK()) { + return rnsd; + } else if(rnsd.status==Result.ERR_Backend) { + return Result.err(rnsd); + } + + // Check if Access to Whole NS + // AAF-724 - Make consistent response for May User", and not take the + // last check... too confusing. + Result rv = mayUserVirtueOfNS(trans, user, ndd, ":" + pdd.ns + ":ns", access.name()); + if (rv.isOK()) { + return rv; + } else { + return Result.err(Status.ERR_Denied, + "[%s] may not %s Perm [%s|%s|%s]", user, access.name(), + pdd.fullType(), pdd.instance, pdd.action); + } + + } + + public Result mayUser(AuthzTrans trans, DelegateDAO.Data dd, Access access) { + try { + Result rnsd = deriveNs(trans, domain2ns(trans.user())); + if(rnsd.isOKhasData() && mayUserVirtueOfNS(trans,trans.user(),rnsd.value, ":" + rnsd.value.name + ":ns", access.name()).isOK()) { + return Result.ok(); + } + boolean isUser = trans.user().equals(dd.user); + boolean isDelegate = dd.delegate != null + && (dd.user.equals(dd.delegate) || trans.user().equals( + dd.delegate)); + Organization org = trans.org(); + switch (access) { + case create: + if (org.getIdentity(trans, dd.user) == null) { + return Result.err(Status.ERR_UserNotFound, + "[%s] is not a user in the company database.", + dd.user); + } + if (!dd.user.equals(dd.delegate) && org.getIdentity(trans, dd.delegate) == null) { + return Result.err(Status.ERR_UserNotFound, + "[%s] is not a user in the company database.", + dd.delegate); + } + if (!trans.requested(REQD_TYPE.force) && dd.user != null && dd.user.equals(dd.delegate)) { + return Result.err(Status.ERR_BadData, + "[%s] cannot be a delegate for self", dd.user); + } + if (!isUser && !isGranted(trans, trans.user(), ROOT_NS,DELG, + org.getDomain(), Question.CREATE)) { + return Result.err(Status.ERR_Denied, + "[%s] may not create a delegate for [%s]", + trans.user(), dd.user); + } + break; + case read: + case write: + if (!isUser && !isDelegate && + !isGranted(trans, trans.user(), ROOT_NS,DELG,org.getDomain(), access.name())) { + return Result.err(Status.ERR_Denied, + "[%s] may not %s delegates for [%s]", trans.user(), + access.name(), dd.user); + } + break; + default: + return Result.err(Status.ERR_BadData,"Unknown Access type [%s]", access.name()); + } + } catch (Exception e) { + return Result.err(e); + } + return Result.ok(); + } + + /* + * Check (recursively, if necessary), if able to do something based on NS + */ + private Result mayUserVirtueOfNS(AuthzTrans trans, String user, NsDAO.Data nsd, String ns_and_type, String access) { + String ns = nsd.name; + + // If an ADMIN of the Namespace, then allow + + Result> rurd; + if ((rurd = userRoleDAO.readUserInRole(trans, user, ns+DOT_ADMIN)).isOKhasData()) { + return Result.ok(nsd); + } else if(rurd.status==Result.ERR_Backend) { + return Result.err(rurd); + } + + // If Specially granted Global Permission + if (isGranted(trans, user, ROOT_NS,NS, ns_and_type, access)) { + return Result.ok(nsd); + } + + // Check recur + + int dot = ns.length(); + if ((dot = ns.lastIndexOf('.', dot - 1)) >= 0) { + Result rnsd = deriveNs(trans, ns.substring(0, dot)); + if (rnsd.isOK()) { + rnsd = mayUserVirtueOfNS(trans, user, rnsd.value, ns_and_type,access); + } else if(rnsd.status==Result.ERR_Backend) { + return Result.err(rnsd); + } + if (rnsd.isOK()) { + return Result.ok(nsd); + } else if(rnsd.status==Result.ERR_Backend) { + return Result.err(rnsd); + } + } + return Result.err(Status.ERR_Denied, "%s may not %s %s", user, access, + ns_and_type); + } + + + /** + * isGranted + * + * Important function - Check internal Permission Schemes for Permission to + * do things + * + * @param trans + * @param type + * @param instance + * @param action + * @return + */ + public boolean isGranted(AuthzTrans trans, String user, String ns, String type,String instance, String action) { + Result> perms = getPermsByUser(trans, user, false); + if (perms.isOK()) { + for (PermDAO.Data pd : perms.value) { + if (ns.equals(pd.ns)) { + if (type.equals(pd.type)) { + if (PermEval.evalInstance(pd.instance, instance)) { + if(PermEval.evalAction(pd.action, action)) { // don't return action here, might miss other action + return true; + } + } + } + } + } + } + return false; + } + + public Result doesUserCredMatch(AuthzTrans trans, String user, byte[] cred) throws DAOException { + Result> result; + TimeTaken tt = trans.start("Read DB Cred", Env.REMOTE); + try { + result = credDAO.readID(trans, user); + } finally { + tt.done(); + } + + Result rv = null; + if(result.isOK()) { + if (result.isEmpty()) { + rv = Result.err(Status.ERR_UserNotFound, user); + if (willSpecialLog(trans,user)) { + trans.audit().log("Special DEBUG:", user, " does not exist in DB"); + } + } else { + Date now = new Date();//long now = System.currentTimeMillis(); + // Bug noticed 6/22. Sorting on the result can cause Concurrency Issues. + List cddl; + if(result.value.size() > 1) { + cddl = new ArrayList(result.value.size()); + for(CredDAO.Data old : result.value) { + if(old.type==CredDAO.BASIC_AUTH || old.type==CredDAO.BASIC_AUTH_SHA256) { + cddl.add(old); + } + } + if(cddl.size()>1) { + Collections.sort(cddl,new Comparator() { + @Override + public int compare(org.onap.aaf.auth.dao.cass.CredDAO.Data a, + org.onap.aaf.auth.dao.cass.CredDAO.Data b) { + return b.expires.compareTo(a.expires); + } + }); + } + } else { + cddl = result.value; + } + + Date expired = null; + StringBuilder debug = willSpecialLog(trans,user)?new StringBuilder():null; + for (CredDAO.Data cdd : cddl) { + if(!cdd.id.equals(user)) { + trans.error().log("doesUserCredMatch DB call does not match for user: " + user); + } + if (cdd.expires.after(now)) { + byte[] dbcred = cdd.cred.array(); + + try { + switch(cdd.type) { + case CredDAO.BASIC_AUTH: + byte[] md5=Hash.hashMD5(cred); + if(Hash.compareTo(md5,dbcred)==0) { + checkLessThanDays(trans,7,now,cdd); + return Result.ok(cdd.expires); + } else if (debug!=null) { + load(debug, cdd,dbcred); + } + break; + case CredDAO.BASIC_AUTH_SHA256: + ByteBuffer bb = ByteBuffer.allocate(Integer.SIZE + cred.length); + bb.putInt(cdd.other); + bb.put(cred); + byte[] hash = Hash.hashSHA256(bb.array()); + + if(Hash.compareTo(hash,dbcred)==0) { + checkLessThanDays(trans,7,now,cdd); + return Result.ok(cdd.expires); + } else if (debug!=null) { + load(debug, cdd, dbcred); + } + break; + default: + trans.error().log("Unknown Credential Type %s for %s, %s",Integer.toString(cdd.type),cdd.id, Chrono.dateTime(cdd.expires)); + } + } catch (NoSuchAlgorithmException e) { + trans.error().log(e); + } + } else { + if(expired==null || expired.before(cdd.expires)) { + expired = cdd.expires; + } + } + } // end for each + if(debug==null) { + debug=new StringBuilder(); + } else { + debug.append(", "); + } + + debug.append("cred="); + debug.append(new String(cred)); + trans.audit().printf("No cred matches ip=%s, user=%s, %s\n",trans.ip(),user,trans.encryptor().encrypt(debug.toString())); + if(expired!=null) { + // Note: this is only returned if there are no good Credentials + rv = Result.err(Status.ERR_Security, + "Credentials %s from %s expired %s",trans.user(), trans.ip(), Chrono.dateTime(expired)); + } + } + } else { + return Result.err(result); + } + return rv == null ? Result.create((Date) null, Status.ERR_Security, "Wrong credential") : rv; + } + + + private void load(StringBuilder debug, Data cdd, byte[] dbcred) { + debug.append("DB Entry: user="); + debug.append(cdd.id); + debug.append(",type="); + debug.append(cdd.type); + debug.append(",cred="); + debug.append(Hash.toHex(dbcred)); + debug.append(",expires="); + debug.append(Chrono.dateTime(cdd.expires)); + debug.append('\n'); + } + + + private void checkLessThanDays(AuthzTrans trans, int days, Date now, Data cdd) { + long close = now.getTime() + (days * 86400000); + long cexp=cdd.expires.getTime(); + if(cexp userCredSetup(AuthzTrans trans, CredDAO.Data cred) { + if(cred.type==CredDAO.RAW) { + TimeTaken tt = trans.start("Hash Cred", Env.SUB); + try { + cred.type = CredDAO.BASIC_AUTH_SHA256; + cred.other = random.nextInt(); + ByteBuffer bb = ByteBuffer.allocate(Integer.SIZE + cred.cred.capacity()); + bb.putInt(cred.other); + bb.put(cred.cred); + byte[] hash = Hash.hashSHA256(bb.array()); + cred.cred = ByteBuffer.wrap(hash); + return Result.ok(cred); + } catch (NoSuchAlgorithmException e) { + return Result.err(Status.ERR_General,e.getLocalizedMessage()); + } finally { + tt.done(); + } + + } + return Result.err(Status.ERR_Security,"invalid/unreadable credential"); + } + + public Result userCredCheck(AuthzTrans trans, CredDAO.Data orig, final byte[] raw) { + TimeTaken tt = trans.start("CheckCred Cred", Env.SUB); + try { + switch(orig.type) { + case CredDAO.BASIC_AUTH_SHA256: + ByteBuffer bb = ByteBuffer.allocate(Integer.SIZE + raw.length); + bb.putInt(orig.other); + bb.put(raw); + return Result.ok(Hash.compareTo(orig.cred.array(),Hash.hashSHA256(bb.array()))==0); + case CredDAO.BASIC_AUTH: + return Result.ok( Hash.compareTo(orig.cred.array(), Hash.hashMD5(raw))==0); + default: + return Result.ok(false); + } + } catch (NoSuchAlgorithmException e) { + return Result.err(Status.ERR_General,e.getLocalizedMessage()); + } finally { + tt.done(); + } + } + + public static final String APPROVED = "APPROVE"; + public static final String REJECT = "REJECT"; + public static final String PENDING = "PENDING"; + + public Result canAddUser(AuthzTrans trans, UserRoleDAO.Data data, + List approvals) { + // get the approval policy for the organization + + // get the list of approvals with an accept status + + // validate the approvals against the policy + + // for now check if all approvals are received and return + // SUCCESS/FAILURE/SKIP + boolean bReject = false; + boolean bPending = false; + + for (ApprovalDAO.Data approval : approvals) { + if (approval.status.equals(REJECT)) { + bReject = true; + } else if (approval.status.equals(PENDING)) { + bPending = true; + } + } + if (bReject) { + return Result.err(Status.ERR_Policy, + "Approval Polocy not conformed"); + } + if (bPending) { + return Result.err(Status.ERR_ActionNotCompleted, + "Required Approvals not received"); + } + + return Result.ok(); + } + + private static final String NO_CACHE_NAME = "No Cache Data named %s"; + + public Result clearCache(AuthzTrans trans, String cname) { + boolean all = "all".equals(cname); + Result rv = null; + + if (all || NsDAO.TABLE.equals(cname)) { + int seg[] = series(NsDAO.CACHE_SEG); + for(int i: seg) {cacheClear(trans, NsDAO.TABLE,i);} + rv = cacheInfoDAO.touch(trans, NsDAO.TABLE, seg); + } + if (all || PermDAO.TABLE.equals(cname)) { + int seg[] = series(NsDAO.CACHE_SEG); + for(int i: seg) {cacheClear(trans, PermDAO.TABLE,i);} + rv = cacheInfoDAO.touch(trans, PermDAO.TABLE,seg); + } + if (all || RoleDAO.TABLE.equals(cname)) { + int seg[] = series(NsDAO.CACHE_SEG); + for(int i: seg) {cacheClear(trans, RoleDAO.TABLE,i);} + rv = cacheInfoDAO.touch(trans, RoleDAO.TABLE,seg); + } + if (all || UserRoleDAO.TABLE.equals(cname)) { + int seg[] = series(NsDAO.CACHE_SEG); + for(int i: seg) {cacheClear(trans, UserRoleDAO.TABLE,i);} + rv = cacheInfoDAO.touch(trans, UserRoleDAO.TABLE,seg); + } + if (all || CredDAO.TABLE.equals(cname)) { + int seg[] = series(NsDAO.CACHE_SEG); + for(int i: seg) {cacheClear(trans, CredDAO.TABLE,i);} + rv = cacheInfoDAO.touch(trans, CredDAO.TABLE,seg); + } + if (all || CertDAO.TABLE.equals(cname)) { + int seg[] = series(NsDAO.CACHE_SEG); + for(int i: seg) {cacheClear(trans, CertDAO.TABLE,i);} + rv = cacheInfoDAO.touch(trans, CertDAO.TABLE,seg); + } + + if (rv == null) { + rv = Result.err(Status.ERR_BadData, NO_CACHE_NAME, cname); + } + return rv; + } + + public Result cacheClear(AuthzTrans trans, String cname,Integer segment) { + Result rv; + if (NsDAO.TABLE.equals(cname)) { + rv = nsDAO.invalidate(segment); + } else if (PermDAO.TABLE.equals(cname)) { + rv = permDAO.invalidate(segment); + } else if (RoleDAO.TABLE.equals(cname)) { + rv = roleDAO.invalidate(segment); + } else if (UserRoleDAO.TABLE.equals(cname)) { + rv = userRoleDAO.invalidate(segment); + } else if (CredDAO.TABLE.equals(cname)) { + rv = credDAO.invalidate(segment); + } else if (CertDAO.TABLE.equals(cname)) { + rv = certDAO.invalidate(segment); + } else { + rv = Result.err(Status.ERR_BadData, NO_CACHE_NAME, cname); + } + return rv; + } + + private int[] series(int max) { + int[] series = new int[max]; + for (int i = 0; i < max; ++i) + series[i] = i; + return series; + } + + public boolean isDelegated(AuthzTrans trans, String user, String approver, Map>> rldd ) { + Result> userDelegatedFor = rldd.get(user); + if(userDelegatedFor==null) { + userDelegatedFor=delegateDAO.readByDelegate(trans, user); + rldd.put(user, userDelegatedFor); + } + if(userDelegatedFor.isOKhasData()) { + for (DelegateDAO.Data curr : userDelegatedFor.value) { + if (curr.user.equals(approver) && curr.delegate.equals(user) + && curr.expires.after(new Date())) { + return true; + } + } + } + return false; + } + + public static boolean willSpecialLog(AuthzTrans trans, String user) { + Boolean b = trans.get(specialLogSlot, null); + if(b==null) { // we haven't evaluated in this trans for Special Log yet + if(specialLog==null) { + return false; + } else { + b = specialLog.contains(user); + trans.put(specialLogSlot, b); + } + } + return b; + } + + public static void logEncryptTrace(AuthzTrans trans, String data) { + long ti; + trans.put(transIDSlot, ti=nextTraceID()); + trans.trace().log("id="+Long.toHexString(ti)+",data=\""+trans.env().encryptor().encrypt(data)+'"'); + } + + private synchronized static long nextTraceID() { + return ++traceID; + } + + public static synchronized boolean specialLogOn(AuthzTrans trans, String id) { + if (specialLog == null) { + specialLog = new HashSet(); + } + boolean rc = specialLog.add(id); + if(rc) { + trans.trace().printf("Trace on for %s requested by %s",id,trans.user()); + } + return rc; + } + + public static synchronized boolean specialLogOff(AuthzTrans trans, String id) { + if(specialLog==null) { + return false; + } + boolean rv = specialLog.remove(id); + if (specialLog.isEmpty()) { + specialLog = null; + } + if(rv) { + trans.trace().printf("Trace off for %s requested by %s",id,trans.user()); + } + return rv; + } + + /** + * canMove + * Which Types can be moved + * @param nsType + * @return + */ + public boolean canMove(NsType nsType) { + boolean rv; + switch(nsType) { + case DOT: + case ROOT: + case COMPANY: + case UNKNOWN: + rv = false; + break; + default: + rv = true; + } + return rv; + } + + public boolean isAdmin(AuthzTrans trans, String user, String ns) { + Date now = new Date(); + Result> rur = userRoleDAO.read(trans, user,ns+DOT_ADMIN); + if(rur.isOKhasData()) {for(UserRoleDAO.Data urdd : rur.value){ + if(urdd.expires.after(now)) { + return true; + } + }}; + return false; + } + + public boolean isOwner(AuthzTrans trans, String user, String ns) { + Result> rur = userRoleDAO.read(trans, user,ns+DOT_OWNER); + Date now = new Date(); + if(rur.isOKhasData()) {for(UserRoleDAO.Data urdd : rur.value){ + if(urdd.expires.after(now)) { + return true; + } + }}; + return false; + } + + public int countOwner(AuthzTrans trans, String ns) { + Result> rur = userRoleDAO.readByRole(trans,ns+DOT_OWNER); + Date now = new Date(); + int count = 0; + if(rur.isOKhasData()) {for(UserRoleDAO.Data urdd : rur.value){ + if(urdd.expires.after(now)) { + ++count; + } + }}; + return count; + } + + /** + * Return a Unique String, (same string, if it is already unique), with only + * lowercase letters, digits and the '.' character. + * + * @param name + * @return + * @throws IOException + */ + public static String toUnique(String name) throws IOException { + byte[] from = name.getBytes(); + StringBuilder sb = new StringBuilder(); + byte f; + for(int i=0;i>4)+0x61)); + sb.append((char)((f&0x0F)+0x61)); + } + return sb.toString(); + } + + public static String fromUnique(String name) throws IOException { + byte[] from = name.getBytes(); + StringBuilder sb = new StringBuilder(); + char c; + for(int i=0;i { + private LocateDAO ldao; + private int major=-1, minor=-1, patch=-1, pkg=-1; + private AuthzEnv env; + private final URI uri; + + /** + * + * @param env + * @param ldao + * @param key must be one or more of service, version, other in that order + * @throws LocatorException + */ + public DirectAAFLocator(AuthzEnv env, LocateDAO ldao, String name, String version) throws LocatorException { + super(env.access(), name, 1000L /* Don't hit DB more than once a second */); + this.env = env; + this.ldao = ldao; + if(version!=null) { + try { + String[] v = Split.split('.',version); + if(v.length>0) {major = Integer.parseInt(v[0]);} + if(v.length>1) {minor = Integer.parseInt(v[1]);} + if(v.length>2) {patch = Integer.parseInt(v[2]);} + if(v.length>3) {pkg = Integer.parseInt(v[3]);} + } catch (NumberFormatException e) { + throw new LocatorException("Invalid Version String: " + version); + } + } + + try { + uri = new URI(access.getProperty(Config.AAF_LOCATE_URL, "localhost")+"/locate/"+name+':'+version); + } catch (URISyntaxException e) { + throw new LocatorException(e); + } + myhostname=null; + myport = 0; + } + + + @Override + public boolean refresh() { + AuthzTrans trans = env.newTransNoAvg(); + Result> rl = ldao.readByName(trans, name); + if(rl.isOK()) { + LinkedList epl = new LinkedList(); + for(Data d : rl.value) { +// if(myhostname!=null && d.port==myport && d.hostname.equals(myhostname)) { +// continue; +// } + if((major<0 || major==d.major) && + (minor<0 || minor<=d.minor) && + (patch<0 || patch==d.patch) && + (pkg<0 || pkg ==d.pkg)) { + Endpoint endpoint = new Endpoint(); + endpoint.setName(d.name); + endpoint.setHostname(d.hostname); + endpoint.setPort(d.port); + endpoint.setMajor(d.major); + endpoint.setMinor(d.minor); + endpoint.setPatch(d.patch); + endpoint.setPkg(d.pkg); + endpoint.setLatitude(d.latitude); + endpoint.setLongitude(d.longitude); + endpoint.setProtocol(d.protocol); + for(String s : d.subprotocol(false)) { + endpoint.getSubprotocol().add(s); + } + + try { + epl.add(new EP(endpoint,latitude,longitude)); + } catch (URISyntaxException e) { + e.printStackTrace(); + } + } + } + Collections.sort(epl); + replace(epl); + return true; + } else { + access.log(Level.ERROR, rl.errorString()); + } + return false; + } + + @Override + protected URI getURI() { + return uri; + } + +} diff --git a/auth/auth-cass/src/main/java/org/onap/aaf/auth/direct/DirectAAFLur.java b/auth/auth-cass/src/main/java/org/onap/aaf/auth/direct/DirectAAFLur.java new file mode 100644 index 00000000..5bdb215e --- /dev/null +++ b/auth/auth-cass/src/main/java/org/onap/aaf/auth/direct/DirectAAFLur.java @@ -0,0 +1,193 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.direct; + +import static org.onap.aaf.auth.layer.Result.OK; + +import java.security.Principal; +import java.util.List; + +import org.onap.aaf.auth.dao.cass.NsSplit; +import org.onap.aaf.auth.dao.cass.PermDAO; +import org.onap.aaf.auth.dao.cass.Status; +import org.onap.aaf.auth.dao.cass.PermDAO.Data; +import org.onap.aaf.auth.dao.hl.Question; +import org.onap.aaf.auth.env.AuthzEnv; +import org.onap.aaf.auth.env.AuthzTrans; +import org.onap.aaf.auth.env.NullTrans; +import org.onap.aaf.auth.layer.Result; +import org.onap.aaf.cadi.Lur; +import org.onap.aaf.cadi.Permission; +import org.onap.aaf.cadi.Access.Level; +import org.onap.aaf.cadi.lur.LocalPermission; +import org.onap.aaf.misc.env.util.Split; + +public class DirectAAFLur implements Lur { + private final AuthzEnv env; + private final Question question; + + public DirectAAFLur(AuthzEnv env, Question question/*, TokenMgr tm*/) { + this.env = env; + this.question = question; +// oauth = new OAuth2Lur(null); + } + + @Override + public boolean fish(Principal bait, Permission pond) { + return fish(env.newTransNoAvg(),bait,pond); + } + + public boolean fish(AuthzTrans trans, Principal bait, Permission pond) { + Result> pdr = question.getPermsByUser(trans, bait.getName(),false); + switch(pdr.status) { + case OK: + for(PermDAO.Data d : pdr.value) { + if(new PermPermission(d).match(pond)) { + return true; + } + } + break; + case Status.ERR_UserRoleNotFound: + case Status.ERR_BadData: + return false; + default: + trans.error().log("Can't access Cassandra to fulfill Permission Query: ",pdr.status,"-",pdr.details); + } + return false; + } + + @Override + public void fishAll(Principal bait, List permissions) { + Result> pdr = question.getPermsByUser(env.newTrans(), bait.getName(),false); + switch(pdr.status) { + case OK: + for(PermDAO.Data d : pdr.value) { + permissions.add(new PermPermission(d)); + } + break; + default: + env.error().log("Can't access Cassandra to fulfill Permission Query: ",pdr.status,"-", pdr.details); + } + } + + @Override + public void destroy() { + } + + @Override + public boolean handlesExclusively(Permission pond) { + return false; + } + + /** + * Small Class implementing CADI's Permission with Cassandra Data + * @author Jonathan + * + */ + public static class PermPermission implements Permission { + private PermDAO.Data data; + + public PermPermission(PermDAO.Data d) { + data = d; + } + + public PermPermission(AuthzTrans trans, Question q, String p) { + data = PermDAO.Data.create(trans, q, p); + } + + public PermPermission(String ns, String type, String instance, String action) { + data = new PermDAO.Data(); + data.ns = ns; + data.type = type; + data.instance = instance; + data.action = action; + } + + @Override + public String getKey() { + return data.type; + } + + @Override + public boolean match(Permission p) { + if(p==null) { + return false; + } + PermDAO.Data pd; + if(p instanceof DirectAAFLur.PermPermission) { + pd = ((DirectAAFLur.PermPermission)p).data; + if(data.ns.equals(pd.ns)) + if(data.type.equals(pd.type)) + if(data.instance!=null && (data.instance.equals(pd.instance) || "*".equals(data.instance))) + if(data.action!=null && (data.action.equals(pd.action) || "*".equals(data.action))) + return true; + } else{ + String[] lp = p.getKey().split("\\|"); + if(lp.length<3)return false; + if(data.fullType().equals(lp[0])) + if(data.instance!=null && (data.instance.equals(lp[1]) || "*".equals(data.instance))) + if(data.action!=null && (data.action.equals(lp[2]) || "*".equals(data.action))) + return true; + } + return false; + } + + @Override + public String permType() { + return "AAFLUR"; + } + + } + + public String toString() { + return "DirectAAFLur is enabled"; + + } + + /* (non-Javadoc) + * @see org.onap.aaf.cadi.Lur#handles(java.security.Principal) + */ + @Override + public boolean handles(Principal principal) { + return true; + } + + @Override + public Permission createPerm(String p) { + String[] params = Split.split('|', p); + if(params.length==3) { + Result nss = question.deriveNsSplit(NullTrans.singleton(), params[0]); + if(nss.isOK()) { + return new PermPermission(nss.value.ns,nss.value.name,params[1],params[2]); + } + } + return new LocalPermission(p); + } + + @Override + public void clear(Principal p, StringBuilder sb) { + AuthzTrans trans = env.newTrans(); + question.clearCache(trans,"all"); + env.log(Level.AUDIT, p.getName(), "has cleared Cache for",getClass().getSimpleName()); + trans.auditTrail(0, sb); + } +} diff --git a/auth/auth-cass/src/main/java/org/onap/aaf/auth/direct/DirectAAFUserPass.java b/auth/auth-cass/src/main/java/org/onap/aaf/auth/direct/DirectAAFUserPass.java new file mode 100644 index 00000000..f241cdf1 --- /dev/null +++ b/auth/auth-cass/src/main/java/org/onap/aaf/auth/direct/DirectAAFUserPass.java @@ -0,0 +1,83 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.direct; + +import static org.onap.aaf.auth.layer.Result.OK; + +import java.util.Date; + +import javax.servlet.http.HttpServletRequest; + +import org.onap.aaf.auth.dao.DAOException; +import org.onap.aaf.auth.dao.hl.Question; +import org.onap.aaf.auth.env.AuthzEnv; +import org.onap.aaf.auth.env.AuthzTrans; +import org.onap.aaf.auth.layer.Result; +import org.onap.aaf.cadi.CredVal; + +/** + * DirectAAFUserPass is intended to provide password Validation directly from Cassandra Database, and is only + * intended for use in AAF itself. The normal "AAF Taf" objects are, of course, clients. + * + * @author Jonathan + * + */ +public class DirectAAFUserPass implements CredVal { + private final AuthzEnv env; + private final Question question; + + public DirectAAFUserPass(AuthzEnv env, Question question) { + this.env = env; + this.question = question; + } + + @Override + public boolean validate(String user, Type type, byte[] pass, Object state) { + try { + AuthzTrans trans; + if(state !=null) { + if(state instanceof AuthzTrans) { + trans = (AuthzTrans)state; + } else { + trans = env.newTransNoAvg(); + if(state instanceof HttpServletRequest) { + trans.set((HttpServletRequest)state); + } + } + } else { + trans = env.newTransNoAvg(); + } + Result result = question.doesUserCredMatch(trans, user, pass); + trans.logAuditTrail(env.info()); + switch(result.status) { + case OK: + return true; + default: + String ip = trans.ip()==null?"":(", ip="+trans.ip()); + env.warn().log(user, "failed password validation" + ip + ':',result.errorString()); + } + } catch (DAOException e) { + env.error().log(e,"Cannot validate user/pass from cassandra"); + } + return false; + } +} diff --git a/auth/auth-cass/src/main/java/org/onap/aaf/auth/direct/DirectCertIdentity.java b/auth/auth-cass/src/main/java/org/onap/aaf/auth/direct/DirectCertIdentity.java new file mode 100644 index 00000000..b5fcd690 --- /dev/null +++ b/auth/auth-cass/src/main/java/org/onap/aaf/auth/direct/DirectCertIdentity.java @@ -0,0 +1,78 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.direct; + +import java.nio.ByteBuffer; +import java.security.cert.CertificateException; +import java.security.cert.X509Certificate; +import java.util.List; + +import javax.servlet.http.HttpServletRequest; + +import org.onap.aaf.auth.dao.cached.CachedCertDAO; +import org.onap.aaf.auth.dao.cass.CertDAO.Data; +import org.onap.aaf.auth.env.AuthzTrans; +import org.onap.aaf.auth.layer.Result; +import org.onap.aaf.auth.rserv.TransFilter; +import org.onap.aaf.cadi.principal.TaggedPrincipal; +import org.onap.aaf.cadi.principal.X509Principal; +import org.onap.aaf.cadi.taf.cert.CertIdentity; +import org.onap.aaf.cadi.taf.cert.X509Taf; + +/** + * Direct view of CertIdentities + * + * Warning: this class is difficult to instantiate. The only service that can use it is AAF itself, and is thus + * entered in the "init" after the CachedCertDAO is created. + * + * @author Jonathan + * + */ +public class DirectCertIdentity implements CertIdentity { + private static CachedCertDAO certDAO; + + @Override + public TaggedPrincipal identity(HttpServletRequest req, X509Certificate cert, byte[] _certBytes) throws CertificateException { + byte[] certBytes = _certBytes; + if(cert==null && certBytes==null) { + return null; + } + if(certBytes==null) { + certBytes = cert.getEncoded(); + } + byte[] fingerprint = X509Taf.getFingerPrint(certBytes); + + AuthzTrans trans = (AuthzTrans) req.getAttribute(TransFilter.TRANS_TAG); + + Result> cresp = certDAO.read(trans, ByteBuffer.wrap(fingerprint)); + if(cresp.isOKhasData()) { + Data cdata = cresp.value.get(0); + return new X509Principal(cdata.id,cert,certBytes); + } + return null; + } + + public static void set(CachedCertDAO ccd) { + certDAO = ccd; + } + +} diff --git a/auth/auth-cass/src/main/java/org/onap/aaf/auth/direct/DirectLocatorCreator.java b/auth/auth-cass/src/main/java/org/onap/aaf/auth/direct/DirectLocatorCreator.java new file mode 100644 index 00000000..3dceb3bf --- /dev/null +++ b/auth/auth-cass/src/main/java/org/onap/aaf/auth/direct/DirectLocatorCreator.java @@ -0,0 +1,59 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.direct; + +import org.onap.aaf.auth.dao.cass.LocateDAO; +import org.onap.aaf.auth.env.AuthzEnv; +import org.onap.aaf.cadi.LocatorException; +import org.onap.aaf.cadi.aaf.v2_0.AbsAAFLocator; + +public class DirectLocatorCreator implements AbsAAFLocator.LocatorCreator { + private final AuthzEnv env; + private final LocateDAO locateDAO; + private String myhostname; + private int myport; + + public DirectLocatorCreator(AuthzEnv env, LocateDAO locateDAO) { + this.env = env; + this.locateDAO = locateDAO; + } + + @Override + public AbsAAFLocator create(String key, String version) throws LocatorException { + DirectAAFLocator dal = new DirectAAFLocator(env,locateDAO,key,version); + if(myhostname!=null) { + dal.setSelf(myhostname, myport); + } + return dal; + } + + /** + * Make sure DirectAAFLocator created does not include self. + * @param hostname + * @param port + */ + public void setSelf(String hostname, int port) { + myhostname = hostname; + myport = port; + } + +} diff --git a/auth/auth-cass/src/main/java/org/onap/aaf/auth/direct/DirectRegistrar.java b/auth/auth-cass/src/main/java/org/onap/aaf/auth/direct/DirectRegistrar.java new file mode 100644 index 00000000..1e8faa2b --- /dev/null +++ b/auth/auth-cass/src/main/java/org/onap/aaf/auth/direct/DirectRegistrar.java @@ -0,0 +1,106 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.direct; + +import java.net.Inet4Address; +import java.net.UnknownHostException; + +import org.onap.aaf.auth.dao.cass.LocateDAO; +import org.onap.aaf.auth.dao.cass.LocateDAO.Data; +import org.onap.aaf.auth.env.AuthzEnv; +import org.onap.aaf.cadi.Access; +import org.onap.aaf.cadi.CadiException; +import org.onap.aaf.cadi.client.Result; +import org.onap.aaf.cadi.config.Config; +import org.onap.aaf.cadi.register.Registrant; +import org.onap.aaf.cadi.util.Split; + +public class DirectRegistrar implements Registrant { + private Data locate; + private LocateDAO ldao; + public DirectRegistrar(Access access, LocateDAO ldao, String name, String version, int port) throws CadiException { + this.ldao = ldao; + locate = new LocateDAO.Data(); + locate.name = name; + locate.port = port; + + try { + String latitude = access.getProperty(Config.CADI_LATITUDE, null); + if(latitude==null) { + latitude = access.getProperty("AFT_LATITUDE", null); + } + String longitude = access.getProperty(Config.CADI_LONGITUDE, null); + if(longitude==null) { + longitude = access.getProperty("AFT_LONGITUDE", null); + } + if(latitude==null || longitude==null) { + throw new CadiException(Config.CADI_LATITUDE + " and " + Config.CADI_LONGITUDE + " is required"); + } else { + locate.latitude = Float.parseFloat(latitude); + locate.longitude = Float.parseFloat(longitude); + } + String split[] = Split.splitTrim('.', version); + locate.pkg = split.length>3?Integer.parseInt(split[3]):0; + locate.patch = split.length>2?Integer.parseInt(split[2]):0; + locate.minor = split.length>1?Integer.parseInt(split[1]):0; + locate.major = split.length>0?Integer.parseInt(split[0]):0; + + locate.hostname = access.getProperty(Config.HOSTNAME, Inet4Address.getLocalHost().getHostName()); + String subprotocols = access.getProperty(Config.CADI_PROTOCOLS, null); + if(subprotocols==null) { + locate.protocol="http"; + } else { + locate.protocol="https"; + for(String s : Split.split(',', subprotocols)) { + locate.subprotocol(true).add(s); + } + } + } catch (NumberFormatException | UnknownHostException e) { + throw new CadiException("Error extracting Data from Properties for Registrar",e); + } + } + + @Override + public Result update(AuthzEnv env) { + org.onap.aaf.auth.layer.Result dr = ldao.update(env.newTransNoAvg(), locate); + if(dr.isOK()) { + return Result.ok(200, null); + } else { + return Result.err(503, dr.errorString()); + } + } + + /* (non-Javadoc) + * @see org.onap.aaf.auth.server.Registrant#cancel(org.onap.aaf.auth.env.test.AuthzEnv) + */ + @Override + public Result cancel(AuthzEnv env) { + org.onap.aaf.auth.layer.Result dr = ldao.delete(env.newTransNoAvg(), locate, false); + if(dr.isOK()) { + return Result.ok(200, null); + } else { + return Result.err(503, dr.errorString()); + } + + } + +} diff --git a/auth/auth-cass/src/test/java/com/att/dao/aaf/test/.gitignore b/auth/auth-cass/src/test/java/com/att/dao/aaf/test/.gitignore new file mode 100644 index 00000000..488b914c --- /dev/null +++ b/auth/auth-cass/src/test/java/com/att/dao/aaf/test/.gitignore @@ -0,0 +1 @@ +/JU_OAuthAppDAO.java diff --git a/auth/auth-cass/src/test/java/com/att/dao/aaf/test/AbsJUCass.java b/auth/auth-cass/src/test/java/com/att/dao/aaf/test/AbsJUCass.java new file mode 100644 index 00000000..5b6a08c5 --- /dev/null +++ b/auth/auth-cass/src/test/java/com/att/dao/aaf/test/AbsJUCass.java @@ -0,0 +1,200 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package com.att.dao.aaf.test; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; +import java.security.NoSuchAlgorithmException; +import java.util.Properties; + +import org.junit.After; +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.BeforeClass; +import org.onap.aaf.auth.dao.CassAccess; +import org.onap.aaf.auth.dao.CassDAOImpl; +import org.onap.aaf.auth.env.AuthzEnv; +import org.onap.aaf.auth.env.AuthzTrans; +import org.onap.aaf.cadi.Hash; +import org.onap.aaf.cadi.Symm; +import org.onap.aaf.misc.env.APIException; +import org.onap.aaf.misc.env.Env; +import org.onap.aaf.misc.env.Trans.Metric; + +import com.datastax.driver.core.Cluster; + +import junit.framework.Assert; + +/** + * Do Setup of Cassandra for Cassandra JUnit Testing + * + * @author Jonathan + * + */ +public class AbsJUCass { + protected static final String AUTHZ = "authz"; + protected static Cluster cluster; + protected static AuthzEnv env; + protected static int iterations = 0; + protected static float totals=0.0f; + protected static float remote = 0.0f; + protected static float json = 0.0f; + protected static AuthzTrans trans; + protected static boolean details = true; + + @BeforeClass + public static void startup() throws APIException, IOException { + try { + synchronized(AUTHZ) { + if(env==null) { + final String resource = "cadi.properties"; + File f = new File("etc" + resource); + InputStream is=null; + Properties props = new Properties(); + try { + if(f.exists()) { + is = new FileInputStream(f); + } else { + URL rsrc = ClassLoader.getSystemResource(resource); + is = rsrc.openStream(); + } + props.load(is); + } finally { + if(is==null) { + env= new AuthzEnv(); + Assert.fail(resource + " must exist in etc dir, or in Classpath"); + } + is.close(); + } + env = new AuthzEnv(props); + } + } + cluster = CassAccess.cluster(env,"LOCAL"); + + env.info().log("Connecting to Cluster"); + try { + cluster.connect(AUTHZ); + } catch(Exception e) { + cluster=null; + env.error().log(e); + Assert.fail("Not able to connect to DB: " + e.getLocalizedMessage()); + } + env.info().log("Connected"); + + // Load special data here + + iterations = 0; + } catch (Throwable t) { + t.printStackTrace(); + throw t; + } + } + + @AfterClass + public static void shutdown() { + if(cluster!=null) { + cluster.close(); + cluster = null; + } + } + + @Before + public void newTrans() { + trans = env.newTrans(); + + trans.setProperty(CassDAOImpl.USER_NAME, System.getProperty("user.name")); + } + + @After + public void auditTrail() { + if(totals==0) { // "updateTotals()" was not called... just do one Trans + StringBuilder sb = new StringBuilder(); + Metric metric = trans.auditTrail(4, sb, Env.JSON, Env.REMOTE); + if(details) { + env.info().log( + sb, + "Total time:", + totals += metric.total, + "JSON time: ", + metric.buckets[0], + "REMOTE time: ", + metric.buckets[1] + ); + } else { + totals += metric.total; + } + } + } + + protected void updateTotals() { + Metric metric = trans.auditTrail(0, null, Env.JSON, Env.REMOTE); + totals+=metric.total; + json +=metric.buckets[0]; + remote+=metric.buckets[1]; + } + + + @AfterClass + public static void print() { + float transTime; + if(iterations==0) { + transTime=totals; + } else { + transTime=totals/iterations; + } + env.info().log( + "Total time:", + totals, + "JSON time:", + json, + "REMOTE time:", + remote, + "Iterations:", + iterations, + "Transaction time:", + transTime + ); + } + + /** + * Take a User/Pass and turn into an MD5 Hashed BasicAuth + * + * @param user + * @param pass + * @return + * @throws IOException + * @throws NoSuchAlgorithmException + */ + public static byte[] userPassToBytes(String user, String pass) + throws IOException, NoSuchAlgorithmException { + // Take the form of BasicAuth, so as to allow any character in Password + // (this is an issue in 1.0) + // Also, it makes it quicker to evaluate Basic Auth direct questions + String ba = Symm.base64url.encode(user + ':' + pass); + // Take MD5 Hash, so that data in DB can't be reversed out. + return Hash.hashMD5(ba.getBytes()); + } + +} diff --git a/auth/auth-cass/src/test/java/com/att/dao/aaf/test/JU_ApprovalDAO.java b/auth/auth-cass/src/test/java/com/att/dao/aaf/test/JU_ApprovalDAO.java new file mode 100644 index 00000000..bc860d0a --- /dev/null +++ b/auth/auth-cass/src/test/java/com/att/dao/aaf/test/JU_ApprovalDAO.java @@ -0,0 +1,153 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package com.att.dao.aaf.test; + + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import java.util.Date; +import java.util.List; +import java.util.UUID; + +import org.junit.Test; +import org.onap.aaf.auth.dao.cass.ApprovalDAO; +import org.onap.aaf.auth.dao.cass.ApprovalDAO.Data; +import org.onap.aaf.auth.layer.Result; + +public class JU_ApprovalDAO extends AbsJUCass { + @Test + public void testCRUD() throws Exception { + ApprovalDAO rrDAO = new ApprovalDAO(trans, cluster, AUTHZ); + ApprovalDAO.Data data = new ApprovalDAO.Data(); + + // Note, Create creates the time id + data.ticket = UUID.randomUUID(); // normally, read from Future object + data.user = "testid@test.com"; + data.approver = "mySuper@att.com"; + data.type = "supervisor"; + data.status = "pending"; + data.operation = "C"; + data.updated = new Date(); + data.memo = "Sing Hey for the break of day"; + data.last_notified = null; + + try { + // Test create + Result rc = rrDAO.create(trans, data); + if(rc.isOKhasData()) { // Create creates the TIMEID. + data = rc.value; + } + + // Test Read by Ticket + Result> rlad; + rlad = rrDAO.readByTicket(trans, data.ticket); + assertTrue(rlad.isOK()); + assertEquals(1,rlad.value.size()); + compare(data,rlad.value.get(0)); + + // Hold onto original ID for deletion, and read tests + UUID id = rlad.value.get(0).id; + + try { + // Test Read by User + rlad = rrDAO.readByUser(trans, data.user); + assertTrue(rlad.isOKhasData()); + boolean ok = false; + for(ApprovalDAO.Data a : rlad.value) { + if(a.id.equals(id)) { + ok = true; + compare(data,a); + } + } + assertTrue(ok); + + // Test Read by Approver + rlad = rrDAO.readByApprover(trans, data.approver); + assertTrue(rlad.isOKhasData()); + ok = false; + for(ApprovalDAO.Data a : rlad.value) { + if(a.id.equals(id)) { + ok = true; + compare(data,a); + } + } + assertTrue(ok); + + // Test Read by ID + rlad = rrDAO.read(trans, id); + assertTrue(rlad.isOKhasData()); + ok = false; + for(ApprovalDAO.Data a : rlad.value) { + if(a.id.equals(id)) { + ok = true; + compare(data,a); + } + } + assertTrue(ok); + + // Test Update + data.status = "approved"; + data.id = id; + assertTrue(rrDAO.update(trans, data).isOK()); + + rlad = rrDAO.read(trans, id); + assertTrue(rlad.isOKhasData()); + ok = false; + for(ApprovalDAO.Data a : rlad.value) { + if(a.id.equals(id)) { + ok = true; + compare(data,a); + } + } + assertTrue(ok); + + } finally { + // Delete + data.id = id; + rrDAO.delete(trans, data, true); + rlad = rrDAO.read(trans, id); + assertTrue(rlad.isOK()); + assertTrue(rlad.isEmpty()); + } + + } finally { + rrDAO.close(trans); + } + } + + private void compare(Data d1, Data d2) { + assertEquals(d1.id.toString(),d2.id.toString()); + assertEquals(d1.ticket.toString(),d2.ticket.toString()); + assertEquals(d1.user,d2.user); + assertEquals(d1.approver,d2.approver); + assertEquals(d1.type,d2.type); + assertEquals(d1.status,d2.status); + assertEquals(d1.operation,d2.operation); + //assertEquals(d1.updated,d2.updated); + assertEquals(d1.memo,d2.memo); + assertEquals(d1.last_notified,d2.last_notified); + } + + + +} diff --git a/auth/auth-cass/src/test/java/com/att/dao/aaf/test/JU_ArtiDAO.java b/auth/auth-cass/src/test/java/com/att/dao/aaf/test/JU_ArtiDAO.java new file mode 100644 index 00000000..e104cbe5 --- /dev/null +++ b/auth/auth-cass/src/test/java/com/att/dao/aaf/test/JU_ArtiDAO.java @@ -0,0 +1,137 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package com.att.dao.aaf.test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import java.io.IOException; +import java.nio.ByteBuffer; +import java.security.NoSuchAlgorithmException; +import java.util.Date; +import java.util.List; + +import org.junit.Test; +import org.onap.aaf.auth.dao.CassAccess; +import org.onap.aaf.auth.dao.cass.ArtiDAO; +import org.onap.aaf.auth.dao.cass.ArtiDAO.Data; +import org.onap.aaf.auth.layer.Result; + +/** + * UserDAO unit test. + * Date: 7/19/13 + */ +public class JU_ArtiDAO extends AbsJUCass { + @Test + public void test() throws IOException, NoSuchAlgorithmException { + ArtiDAO adao = new ArtiDAO(trans,cluster,CassAccess.KEYSPACE); + try { + // TODO: Clean out AT&T specific data + // Create + ArtiDAO.Data data = new ArtiDAO.Data(); + data.mechid="m553j5@perturbed.onap.org"; + data.machine="perturbed1232.onap.org"; + data.type(false).add("file"); + data.type(false).add("jks"); + data.sponsor="Fred Flintstone"; + data.ca="devl"; + data.dir="/opt/app/aft/keys"; + data.ns="kumquat"; + data.os_user="aft"; + data.notify="email:fred@bogus.com"; + data.expires=new Date(); + +// Bytification + ByteBuffer bb = data.bytify(); + Data bdata = new ArtiDAO.Data(); + bdata.reconstitute(bb); + checkData1(data, bdata); + + +// DB work + adao.create(trans,data); + try { + // Validate Read with key fields in Data + Result> rlcd = adao.read(trans,data); + assertTrue(rlcd.isOKhasData()); + for(ArtiDAO.Data d : rlcd.value) { + checkData1(data,d); + } + + // Validate Read with key fields in Data + rlcd = adao.read(trans,data.mechid, data.machine); + assertTrue(rlcd.isOKhasData()); + for(ArtiDAO.Data d : rlcd.value) { + checkData1(data,d); + } + + // By Machine + rlcd = adao.readByMachine(trans,data.machine); + assertTrue(rlcd.isOKhasData()); + for(ArtiDAO.Data d : rlcd.value) { + checkData1(data,d); + } + + // By MechID + rlcd = adao.readByMechID(trans,data.mechid); + assertTrue(rlcd.isOKhasData()); + for(ArtiDAO.Data d : rlcd.value) { + checkData1(data,d); + } + + // Update + data.sponsor = "Wilma Flintstone"; + adao.update(trans,data); + rlcd = adao.read(trans,data); + assertTrue(rlcd.isOKhasData()); + for(ArtiDAO.Data d : rlcd.value) { + checkData1(data,d); + } + + } finally { + // Always delete data, even if failure. + adao.delete(trans,data, true); + } + } finally { + adao.close(trans); + } + + + } + + private void checkData1(Data data, Data d) { + assertEquals(data.mechid,d.mechid); + assertEquals(data.machine,d.machine); + assertEquals(data.type(false).size(),d.type(false).size()); + for(String s: data.type(false)) { + assertTrue(d.type(false).contains(s)); + } + assertEquals(data.sponsor,d.sponsor); + assertEquals(data.ca,d.ca); + assertEquals(data.dir,d.dir); + assertEquals(data.ns,d.ns); + assertEquals(data.os_user,d.os_user); + assertEquals(data.notify,d.notify); + assertEquals(data.expires,d.expires); + } + +} diff --git a/auth/auth-cass/src/test/java/com/att/dao/aaf/test/JU_Bytification.java b/auth/auth-cass/src/test/java/com/att/dao/aaf/test/JU_Bytification.java new file mode 100644 index 00000000..206c52a7 --- /dev/null +++ b/auth/auth-cass/src/test/java/com/att/dao/aaf/test/JU_Bytification.java @@ -0,0 +1,266 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package com.att.dao.aaf.test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import java.io.IOException; +import java.nio.ByteBuffer; +import java.util.Date; + +import org.junit.Test; +import org.onap.aaf.auth.dao.cass.CredDAO; +import org.onap.aaf.auth.dao.cass.NsDAO; +import org.onap.aaf.auth.dao.cass.NsType; +import org.onap.aaf.auth.dao.cass.PermDAO; +import org.onap.aaf.auth.dao.cass.RoleDAO; +import org.onap.aaf.auth.dao.cass.UserRoleDAO; + +public class JU_Bytification { + + @Test + public void testNS() throws IOException { + + // Normal + NsDAO.Data ns = new NsDAO.Data(); + ns.name = "org.osaaf.whatever"; + ns.type = NsType.APP.type; + + ByteBuffer bb = ns.bytify(); + + NsDAO.Data nsr = new NsDAO.Data(); + nsr.reconstitute(bb); + check(ns,nsr); + + // Empty admin +// ns.admin(true).clear(); + bb = ns.bytify(); + nsr = new NsDAO.Data(); + nsr.reconstitute(bb); + check(ns,nsr); + + // Empty responsible +// ns.responsible(true).clear(); + bb = ns.bytify(); + nsr = new NsDAO.Data(); + nsr.reconstitute(bb); + check(ns,nsr); + + bb = ns.bytify(); + nsr = new NsDAO.Data(); + nsr.reconstitute(bb); + check(ns,nsr); + } + + private void check(NsDAO.Data a, NsDAO.Data b) { + assertEquals(a.name,b.name); + assertEquals(a.type,b.type); +// assertEquals(a.admin.size(),b.admin.size()); + +// for(String s: a.admin) { +// assertTrue(b.admin.contains(s)); +// } +// +// assertEquals(a.responsible.size(),b.responsible.size()); +// for(String s: a.responsible) { +// assertTrue(b.responsible.contains(s)); +// } + } + + @Test + public void testRole() throws IOException { + RoleDAO.Data rd1 = new RoleDAO.Data(); + rd1.ns = "org.osaaf.whatever"; + rd1.name = "my.role"; + rd1.perms(true).add("org.osaaf.whatever.my.Perm|myInstance|myAction"); + rd1.perms(true).add("org.osaaf.whatever.my.Perm|myInstance|myAction2"); + + // Normal + ByteBuffer bb = rd1.bytify(); + RoleDAO.Data rd2 = new RoleDAO.Data(); + rd2.reconstitute(bb); + check(rd1,rd2); + + // Overshoot Buffer + StringBuilder sb = new StringBuilder(300); + sb.append("role|instance|veryLongAction..."); + for(int i=0;i<280;++i) { + sb.append('a'); + } + rd1.perms(true).add(sb.toString()); + bb = rd1.bytify(); + rd2 = new RoleDAO.Data(); + rd2.reconstitute(bb); + check(rd1,rd2); + + // No Perms + rd1.perms.clear(); + + bb = rd1.bytify(); + rd2 = new RoleDAO.Data(); + rd2.reconstitute(bb); + check(rd1,rd2); + + // 1000 Perms + for(int i=0;i<1000;++i) { + rd1.perms(true).add("com|inst|action"+ i); + } + + bb = rd1.bytify(); + rd2 = new RoleDAO.Data(); + rd2.reconstitute(bb); + check(rd1,rd2); + + } + + private void check(RoleDAO.Data a, RoleDAO.Data b) { + assertEquals(a.ns,b.ns); + assertEquals(a.name,b.name); + + assertEquals(a.perms.size(),b.perms.size()); + for(String s: a.perms) { + assertTrue(b.perms.contains(s)); + } + } + + @Test + public void testPerm() throws IOException { + PermDAO.Data pd1 = new PermDAO.Data(); + pd1.ns = "org.osaaf.whatever"; + pd1.type = "my.perm"; + pd1.instance = "instance"; + pd1.action = "read"; + pd1.roles(true).add("org.osaaf.whatever.my.Role"); + pd1.roles(true).add("org.osaaf.whatever.my.Role2"); + + // Normal + ByteBuffer bb = pd1.bytify(); + PermDAO.Data rd2 = new PermDAO.Data(); + rd2.reconstitute(bb); + check(pd1,rd2); + + // No Perms + pd1.roles.clear(); + + bb = pd1.bytify(); + rd2 = new PermDAO.Data(); + rd2.reconstitute(bb); + check(pd1,rd2); + + // 1000 Perms + for(int i=0;i<1000;++i) { + pd1.roles(true).add("org.osaaf.whatever.my.Role"+ i); + } + + bb = pd1.bytify(); + rd2 = new PermDAO.Data(); + rd2.reconstitute(bb); + check(pd1,rd2); + + } + + private void check(PermDAO.Data a, PermDAO.Data b) { + assertEquals(a.ns,b.ns); + assertEquals(a.type,b.type); + assertEquals(a.instance,b.instance); + assertEquals(a.action,b.action); + + assertEquals(a.roles.size(),b.roles.size()); + for(String s: a.roles) { + assertTrue(b.roles.contains(s)); + } + } + + @Test + public void testUserRole() throws IOException { + UserRoleDAO.Data urd1 = new UserRoleDAO.Data(); +// TODO: Clean out AT&T specific data + urd1.user = "jg1555@abc.att.com"; + urd1.role("org.osaaf.whatever","my.role"); + urd1.expires = new Date(); + + // Normal + ByteBuffer bb = urd1.bytify(); + UserRoleDAO.Data urd2 = new UserRoleDAO.Data(); + urd2.reconstitute(bb); + check(urd1,urd2); + + // A null + urd1.expires = null; + urd1.role = null; + + bb = urd1.bytify(); + urd2 = new UserRoleDAO.Data(); + urd2.reconstitute(bb); + check(urd1,urd2); + } + + private void check(UserRoleDAO.Data a, UserRoleDAO.Data b) { + assertEquals(a.user,b.user); + assertEquals(a.role,b.role); + assertEquals(a.expires,b.expires); + } + + + @Test + public void testCred() throws IOException { + CredDAO.Data cd = new CredDAO.Data(); + cd.id = "m55555@abc.att.com"; + cd.ns = "org.osaaf.abc"; + cd.type = 2; + cd.cred = ByteBuffer.wrap(new byte[]{1,34,5,3,25,0,2,5,3,4}); + cd.expires = new Date(); + + // Normal + ByteBuffer bb = cd.bytify(); + CredDAO.Data cd2 = new CredDAO.Data(); + cd2.reconstitute(bb); + check(cd,cd2); + + // nulls + cd.expires = null; + cd.cred = null; + + bb = cd.bytify(); + cd2 = new CredDAO.Data(); + cd2.reconstitute(bb); + check(cd,cd2); + + } + + private void check(CredDAO.Data a, CredDAO.Data b) { + assertEquals(a.id,b.id); + assertEquals(a.ns,b.ns); + assertEquals(a.type,b.type); + if(a.cred==null) { + assertEquals(a.cred,b.cred); + } else { + int l = a.cred.limit(); + assertEquals(l,b.cred.limit()); + for (int i=0;i id = new CacheInfoDAO(trans, cluster, AUTHZ); + Date date = new Date(); + + id.touch(trans, RoleDAO.TABLE,1); + try { + Thread.sleep(3000); + } catch (InterruptedException e) { + } + Result rid = id.check(trans); + Assert.assertEquals(rid.status,Status.OK); + Date[] dates = CacheInfoDAO.info.get(RoleDAO.TABLE); + if(dates.length>0 && dates[1]!=null) { + System.out.println(Chrono.dateStamp(dates[1])); + System.out.println(Chrono.dateStamp(date)); + Assert.assertTrue(Math.abs(dates[1].getTime() - date.getTime())<20000); // allow for 4 seconds, given Remote DB + } + } + +} diff --git a/auth/auth-cass/src/test/java/com/att/dao/aaf/test/JU_CertDAO.java b/auth/auth-cass/src/test/java/com/att/dao/aaf/test/JU_CertDAO.java new file mode 100644 index 00000000..cd3fb8d0 --- /dev/null +++ b/auth/auth-cass/src/test/java/com/att/dao/aaf/test/JU_CertDAO.java @@ -0,0 +1,103 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package com.att.dao.aaf.test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import java.io.IOException; +import java.math.BigInteger; +import java.nio.ByteBuffer; +import java.security.NoSuchAlgorithmException; +import java.util.List; + +import org.junit.Test; +import org.onap.aaf.auth.dao.CassAccess; +import org.onap.aaf.auth.dao.cass.CertDAO; +import org.onap.aaf.auth.dao.cass.CertDAO.Data; +import org.onap.aaf.auth.layer.Result; +import org.onap.aaf.misc.env.APIException; + +/** + * UserDAO unit test. + * Date: 7/19/13 + */ +public class JU_CertDAO extends AbsJUCass { + @Test + public void test() throws IOException, NoSuchAlgorithmException, APIException { + CertDAO cdao = new CertDAO(trans,cluster,CassAccess.KEYSPACE); + try { + // Create + CertDAO.Data data = new CertDAO.Data(); + data.serial=new BigInteger("11839383"); + data.id = "m55555@tguard.att.com"; + data.x500="CN=ju_cert.dao.att.com, OU=AAF, O=\"ATT Services, Inc.\", L=Southfield, ST=Michigan, C=US"; + data.x509="I'm a cert"; + data.ca = "aaf"; + cdao.create(trans,data); + +// Bytification + ByteBuffer bb = data.bytify(); + Data bdata = new CertDAO.Data(); + bdata.reconstitute(bb); + checkData1(data, bdata); + + // Validate Read with key fields in Data + Result> rlcd = cdao.read(trans,data); + assertTrue(rlcd.isOKhasData()); + for(CertDAO.Data d : rlcd.value) { + checkData1(data,d); + } + + // Validate Read with key fields in Data + rlcd = cdao.read(trans,data.ca,data.serial); + assertTrue(rlcd.isOKhasData()); + for(CertDAO.Data d : rlcd.value) { + checkData1(data,d); + } + + // Update + data.id = "m66666.tguard.att.com"; + cdao.update(trans,data); + rlcd = cdao.read(trans,data); + assertTrue(rlcd.isOKhasData()); + for(CertDAO.Data d : rlcd.value) { + checkData1(data,d); + } + + cdao.delete(trans,data, true); + } finally { + cdao.close(trans); + } + + + } + + private void checkData1(Data data, Data d) { + assertEquals(data.ca,d.ca); + assertEquals(data.serial,d.serial); + assertEquals(data.id,d.id); + assertEquals(data.x500,d.x500); + assertEquals(data.x509,d.x509); + } + +} diff --git a/auth/auth-cass/src/test/java/com/att/dao/aaf/test/JU_CredDAO.java b/auth/auth-cass/src/test/java/com/att/dao/aaf/test/JU_CredDAO.java new file mode 100644 index 00000000..3ccc4320 --- /dev/null +++ b/auth/auth-cass/src/test/java/com/att/dao/aaf/test/JU_CredDAO.java @@ -0,0 +1,250 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package com.att.dao.aaf.test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import java.io.IOException; +import java.nio.ByteBuffer; +import java.security.NoSuchAlgorithmException; +import java.util.Date; +import java.util.List; + +import org.junit.Test; +import org.onap.aaf.auth.dao.CassAccess; +import org.onap.aaf.auth.dao.cass.CredDAO; +import org.onap.aaf.auth.dao.cass.CredDAO.Data; +import org.onap.aaf.auth.layer.Result; +import org.onap.aaf.misc.env.APIException; + +/** + * UserDAO unit test. + * Date: 7/19/13 + */ +public class JU_CredDAO extends AbsJUCass { + @Test + public void test() throws IOException, NoSuchAlgorithmException, APIException { + CredDAO udao = new CredDAO(trans,cluster,CassAccess.KEYSPACE); + try { + // Create + CredDAO.Data data = new CredDAO.Data(); + data.id = "m55555@aaf.att.com"; + data.type = CredDAO.BASIC_AUTH; + data.notes = "temp pass"; + data.cred = ByteBuffer.wrap(userPassToBytes("m55555","mypass")); + data.other = 12; + data.expires = new Date(System.currentTimeMillis() + 60000*60*24*90); + udao.create(trans,data); + +// Bytification + ByteBuffer bb = data.bytify(); + Data bdata = new CredDAO.Data(); + bdata.reconstitute(bb); + checkData1(data, bdata); + + // Validate Read with key fields in Data + Result> rlcd = udao.read(trans,data); + assertTrue(rlcd.isOKhasData()); + for(CredDAO.Data d : rlcd.value) { + checkData1(data,d); + } + + // Update + data.cred = ByteBuffer.wrap(userPassToBytes("m55555","mynewpass")); + udao.update(trans,data); + rlcd = udao.read(trans,data); + assertTrue(rlcd.isOKhasData()); + for(CredDAO.Data d : rlcd.value) { + checkData1(data,d); + } + + udao.delete(trans,data, true); + } finally { + udao.close(trans); + } + + + } + + private void checkData1(Data data, Data d) { + assertEquals(data.id,d.id); + assertEquals(data.type,d.type); + assertEquals(data.ns,d.ns); + assertEquals(data.notes,d.notes); + assertEquals(data.cred,d.cred); + assertEquals(data.other,d.other); + assertEquals(data.expires,d.expires); + } + +// private String CONST_myName = "MyName"; +// public static final java.nio.ByteBuffer CONST_MY_CRED = get_CONST_MY_CRED(); +// public static final int CONST_CRED_TYPE = 11; +// +// public static final Date CONST_UPDATE_DATE = new Date(System.currentTimeMillis()+60000*24); +// @Test +// public void test() { +// UserDAO ud = new UserDAO(trans, cluster,CassAccess.KEYSPACE); +// try { +// UserDAO.Data data = createPrototypeUserData(); +// ud.create(trans, data); +// +// // Validate Read with key fields in Data +// for(UserDAO.Data d : ud.read(trans, data)) { +// checkData1(data,d); +// } +// +// // Validate readByName +// for(UserDAO.Data d : ud.read(trans, CONST_myName)) { +// checkData1(data,d); +// } +// +// ud.delete(trans, data); +// List d_2 = ud.read(trans, CONST_myName); +// +// // Validate that data was deleted +// assertEquals("User should not be found after deleted", 0, d_2.size() ); +// +// data = new UserDAO.Data(); +// data.name = CONST_myName; +// data.cred = CONST_MY_CRED; +// data.cred_type= CONST_CRED_TYPE; +// data.expires = new Date(System.currentTimeMillis()+60000*24); +// final Result user = ud.r_create(trans, data); +// assertEquals("ud.createUser should work", Result.Status.OK, user.status); +// +// checkDataIgnoreDateDiff(data, user.value); +// +// // finally leave system in consistent state by deleting user again +// ud.delete(trans,data); +// +// } catch (DAOException e) { +// e.printStackTrace(); +// fail("Fail due to Exception"); +// } finally { +// ud.close(trans); +// } +// } +// +// private UserDAO.Data createPrototypeUserData() { +// UserDAO.Data data = new UserDAO.Data(); +// data.name = CONST_myName; +// +// data.cred_type = CONST_CRED_TYPE; +// data.cred = CONST_MY_CRED; +// data.expires = CONST_UPDATE_DATE; +// return data; +// } +// +// // @Test +// // public void testReadByUser() throws Exception { +// // // this test was done above in our super test, since it uses the same setup +// // } +// +// @Test +// public void testFunctionCreateUser() throws Exception { +// String name = "roger_rabbit"; +// Integer credType = CONST_CRED_TYPE; +// java.nio.ByteBuffer cred = CONST_MY_CRED; +// final UserDAO ud = new UserDAO(trans, cluster,CassAccess.KEYSPACE); +// final UserDAO.Data data = createPrototypeUserData(); +// Result ret = ud.r_create(trans, data); +// Result> byUserNameLookup = ud.r_read(trans, name); +// +// assertEquals("sanity test w/ different username (different than other test cases) failed", name, byUserNameLookup.value.get(0).name); +// assertEquals("delete roger_rabbit failed", true, ud.delete(trans, byUserNameLookup.value.get(0))); +// } +// +// @Test +// public void testLowLevelCassandraCreateData_Given_UserAlreadyPresent_ShouldPass() throws Exception { +// UserDAO ud = new UserDAO(trans, cluster,CassAccess.KEYSPACE); +// +// final UserDAO.Data data = createPrototypeUserData(); +// final UserDAO.Data data1 = ud.create(trans, data); +// final UserDAO.Data data2 = ud.create(trans, data); +// +// assertNotNull(data1); +// assertNotNull(data2); +// +// assertEquals(CONST_myName, data1.name); +// assertEquals(CONST_myName, data2.name); +// } +// +// @Test +// public void testCreateUser_Given_UserAlreadyPresent_ShouldFail() throws Exception { +// UserDAO ud = new UserDAO(trans, cluster,CassAccess.KEYSPACE); +// +// final UserDAO.Data data = createPrototypeUserData(); +// +// // make sure that some prev test did not leave the user in the DB +// ud.delete(trans, data); +// +// // attempt to create same user twice !!! +// +// final Result data1 = ud.r_create(trans, data); +// final Result data2 = ud.r_create(trans, data); +// +// assertNotNull(data1); +// assertNotNull(data2); +// +// assertEquals(true, Result.Status.OK == data1.status); +// assertEquals(false, Result.Status.OK == data2.status); +// } +// +// private void checkData1(UserDAO.Data data, UserDAO.Data d) { +// data.name = CONST_myName; +// +// data.cred_type = CONST_CRED_TYPE; +// data.cred = CONST_MY_CRED; +// data.expires = CONST_UPDATE_DATE; +// +// assertEquals(data.name, d.name); +// assertEquals(data.cred_type, d.cred_type); +// assertEquals(data.cred, d.cred); +// assertEquals(data.expires, d.expires); +// +// } +// +// private void checkDataIgnoreDateDiff(UserDAO.Data data, UserDAO.Data d) { +// data.name = CONST_myName; +// +// data.cred_type = CONST_CRED_TYPE; +// data.cred = CONST_MY_CRED; +// data.expires = CONST_UPDATE_DATE; +// +// assertEquals(data.name, d.name); +// assertEquals(data.cred_type, d.cred_type); +// assertEquals(data.cred, d.cred); +// // we allow dates to be different, e.g. high level calls e.g. createUser sets the date itself. +// //assertEquals(data.updated, d.updated); +// +// } +// +// /** +// * Get a CONST_MY_CRED ByteBuffer, which is the java type for a cass blob. +// * @return +// */ +// private static java.nio.ByteBuffer get_CONST_MY_CRED() { +// return ByteBuffer.wrap("Hello".getBytes()); +// } +// +} diff --git a/auth/auth-cass/src/test/java/com/att/dao/aaf/test/JU_DelegateDAO.java b/auth/auth-cass/src/test/java/com/att/dao/aaf/test/JU_DelegateDAO.java new file mode 100644 index 00000000..1a4d21c4 --- /dev/null +++ b/auth/auth-cass/src/test/java/com/att/dao/aaf/test/JU_DelegateDAO.java @@ -0,0 +1,108 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package com.att.dao.aaf.test; + + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import java.nio.ByteBuffer; +import java.util.Date; +import java.util.List; + +import org.junit.Test; +import org.onap.aaf.auth.dao.cass.DelegateDAO; +import org.onap.aaf.auth.dao.cass.DelegateDAO.Data; +import org.onap.aaf.auth.layer.Result; + + +public class JU_DelegateDAO extends AbsJUCass { + @Test + public void testCRUD() throws Exception { + DelegateDAO dao = new DelegateDAO(trans, cluster, AUTHZ); + DelegateDAO.Data data = new DelegateDAO.Data(); +// TODO: Clean out AT&T specific data + data.user = "jg1555"; + data.delegate = "rd8227"; + data.expires = new Date(); + +// Bytification + ByteBuffer bb = data.bytify(); + Data bdata = new DelegateDAO.Data(); + bdata.reconstitute(bb); + compare(data, bdata); + + try { + // Test create + Result ddcr = dao.create(trans,data); + assertTrue(ddcr.isOK()); + + + // Read by User + Result> records = dao.read(trans,data.user); + assertTrue(records.isOKhasData()); + for(DelegateDAO.Data rdata : records.value) + compare(data,rdata); + + // Read by Delegate + records = dao.readByDelegate(trans,data.delegate); + assertTrue(records.isOKhasData()); + for(DelegateDAO.Data rdata : records.value) + compare(data,rdata); + + // Update + // TODO: Clean out AT&T specific data + data.delegate = "pf2819"; + data.expires = new Date(); + assertTrue(dao.update(trans, data).isOK()); + + // Read by User + records = dao.read(trans,data.user); + assertTrue(records.isOKhasData()); + for(DelegateDAO.Data rdata : records.value) + compare(data,rdata); + + // Read by Delegate + records = dao.readByDelegate(trans,data.delegate); + assertTrue(records.isOKhasData()); + for(DelegateDAO.Data rdata : records.value) + compare(data,rdata); + + // Test delete + dao.delete(trans,data, true); + records = dao.read(trans,data.user); + assertTrue(records.isEmpty()); + + + } finally { + dao.close(trans); + } + } + + private void compare(Data d1, Data d2) { + assertEquals(d1.user, d2.user); + assertEquals(d1.delegate, d2.delegate); + assertEquals(d1.expires,d2.expires); + } + + +} diff --git a/auth/auth-cass/src/test/java/com/att/dao/aaf/test/JU_FastCalling.java b/auth/auth-cass/src/test/java/com/att/dao/aaf/test/JU_FastCalling.java new file mode 100644 index 00000000..9d3ff5db --- /dev/null +++ b/auth/auth-cass/src/test/java/com/att/dao/aaf/test/JU_FastCalling.java @@ -0,0 +1,90 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package com.att.dao.aaf.test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import java.io.IOException; +import java.nio.ByteBuffer; +import java.security.NoSuchAlgorithmException; +import java.util.Date; +import java.util.List; + +import org.junit.Test; +import org.onap.aaf.auth.dao.CassAccess; +import org.onap.aaf.auth.dao.cass.CredDAO; +import org.onap.aaf.auth.dao.cass.CredDAO.Data; +import org.onap.aaf.auth.layer.Result; +import org.onap.aaf.misc.env.APIException; + +public class JU_FastCalling extends AbsJUCass { + + @Test + public void test() throws IOException, NoSuchAlgorithmException, APIException { + trans.setProperty("cassandra.writeConsistency.cred","ONE"); + + CredDAO udao = new CredDAO(env.newTransNoAvg(),cluster,CassAccess.KEYSPACE); + System.out.println("Starting calls"); + for(iterations=0;iterations<8;++iterations) { + try { + // Create + CredDAO.Data data = new CredDAO.Data(); + data.id = "m55555@aaf.att.com"; + data.type = CredDAO.BASIC_AUTH; + data.cred = ByteBuffer.wrap(userPassToBytes("m55555","mypass")); + data.expires = new Date(System.currentTimeMillis() + 60000*60*24*90); + udao.create(trans,data); + + // Validate Read with key fields in Data + Result> rlcd = udao.read(trans,data); + assertTrue(rlcd.isOKhasData()); + for(CredDAO.Data d : rlcd.value) { + checkData1(data,d); + } + + // Update + data.cred = ByteBuffer.wrap(userPassToBytes("m55555","mynewpass")); + udao.update(trans,data); + rlcd = udao.read(trans,data); + assertTrue(rlcd.isOKhasData()); + for(CredDAO.Data d : rlcd.value) { + checkData1(data,d); + } + + udao.delete(trans,data, true); + } finally { + updateTotals(); + newTrans(); + } + } + + } + + private void checkData1(Data data, Data d) { + assertEquals(data.id,d.id); + assertEquals(data.type,d.type); + assertEquals(data.cred,d.cred); + assertEquals(data.expires,d.expires); + } + +} diff --git a/auth/auth-cass/src/test/java/com/att/dao/aaf/test/JU_HistoryDAO.java b/auth/auth-cass/src/test/java/com/att/dao/aaf/test/JU_HistoryDAO.java new file mode 100644 index 00000000..11d88358 --- /dev/null +++ b/auth/auth-cass/src/test/java/com/att/dao/aaf/test/JU_HistoryDAO.java @@ -0,0 +1,153 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package com.att.dao.aaf.test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +import java.nio.ByteBuffer; +import java.security.SecureRandom; +import java.util.List; + +import org.junit.Test; +import org.onap.aaf.auth.dao.cass.HistoryDAO; +import org.onap.aaf.auth.layer.Result; + +public class JU_HistoryDAO extends AbsJUCass { + + @Test + public void testCreate() throws Exception { + HistoryDAO historyDAO = new HistoryDAO(trans, cluster, AUTHZ); + HistoryDAO.Data data = createHistoryData(); + + try { + historyDAO.create(trans,data); + Thread.sleep(200);// History Create is Async + Result> records = historyDAO.readByUser(trans,data.user,data.yr_mon); + assertTrue(records.isOKhasData()); + for(HistoryDAO.Data d : records.value) { + assertHistory(data, d); + } + } finally { + historyDAO.close(trans); + } + } + + @Test + public void tesReadByUser() throws Exception { + HistoryDAO historyDAO = new HistoryDAO(trans,cluster, AUTHZ); + HistoryDAO.Data data = createHistoryData(); + + try { + historyDAO.create(trans,data); + Thread.sleep(200);// History Create is Async + Result> records = historyDAO.readByUser(trans, data.user,data.yr_mon); + assertTrue(records.isOKhasData()); + for(HistoryDAO.Data d : records.value) { + assertHistory(data, d); + } + } finally { + historyDAO.close(trans); + } + } + +/* + @Test + public void readByUserAndMonth() throws Exception { + HistoryDAO historyDAO = new HistoryDAO(trans,cluster, AUTHZ); + HistoryDAO.Data data = createHistoryData(); + + try { + historyDAO.create(trans,data); + Thread.sleep(200);// History Create is Async + Result> records = historyDAO.readByUserAndMonth(trans, + data.user, Integer.valueOf(String.valueOf(data.yr_mon).substring(0, 4)), + Integer.valueOf(String.valueOf(data.yr_mon).substring(4, 6))); + assertTrue(records.isOKhasData()); + for(HistoryDAO.Data d : records.value) { + assertHistory(data, d); + } + } finally { + historyDAO.close(trans); + } + } +*/ + //TODO readadd this +// @Test +// public void readByUserAndDay() throws Exception { +// HistoryDAO historyDAO = new HistoryDAO(trans, cluster, AUTHZ); +// HistoryDAO.Data data = createHistoryData(); +// +// try { +// historyDAO.create(trans, data); +// Thread.sleep(200);// History Create is Async +// +// String dayTime = String.valueOf(data.day_time); +// String day = null; +// if (dayTime.length() < 8) +// day = dayTime.substring(0, 1); +// else +// day = dayTime.substring(0, 2); +// +// List records = historyDAO.readByUserBetweenDates(trans, +// data.user, Integer.valueOf(String.valueOf(data.yr_mon).substring(0, 4)), +// Integer.valueOf(String.valueOf(data.yr_mon).substring(4, 6)), +// Integer.valueOf(day), 0); +// assertEquals(1,records.size()); +// for(HistoryDAO.Data d : records) { +// assertHistory(data, d); +// } +// } finally { +// historyDAO.close(trans); +// } +// } + private HistoryDAO.Data createHistoryData() { + HistoryDAO.Data data = HistoryDAO.newInitedData(); + SecureRandom random = new SecureRandom(); + data.user = "test" + random.nextInt(); + data.action = "add"; + data.target = "history"; + data.memo = "adding a row into history table"; +// data.detail().put("id", "test"); +// data.detail().put("name", "test"); + //String temp = "Test Blob Message"; + data.reconstruct = ByteBuffer.wrap("Temp Blob Message".getBytes()); + return data; + } + + private void assertHistory(HistoryDAO.Data ip, HistoryDAO.Data op) { + assertEquals(ip.yr_mon, op.yr_mon); +// assertEquals(ip.day_time, op.day_time); + assertEquals(ip.user, op.user); + assertEquals(ip.action, op.action); + assertEquals(ip.target, op.target); + assertEquals(ip.memo, op.memo); + //TODO : have to see if third party assert utility can be used +// assertTrue(CollectionUtils.isEqualCollection(ip.detail, op.detail)); +// for (String key : ip.detail().keySet()) { +// assertNotNull(op.detail().get(key)); +// } + assertNotNull(op.reconstruct); + } + +} diff --git a/auth/auth-cass/src/test/java/com/att/dao/aaf/test/JU_LocateDAO.java b/auth/auth-cass/src/test/java/com/att/dao/aaf/test/JU_LocateDAO.java new file mode 100644 index 00000000..283a3563 --- /dev/null +++ b/auth/auth-cass/src/test/java/com/att/dao/aaf/test/JU_LocateDAO.java @@ -0,0 +1,146 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package com.att.dao.aaf.test; + +import static junit.framework.Assert.assertEquals; +import static junit.framework.Assert.assertTrue; + +import java.io.IOException; +import java.nio.ByteBuffer; +import java.util.List; +import java.util.Set; + +import org.junit.Test; +import org.onap.aaf.auth.dao.CassAccess; +import org.onap.aaf.auth.dao.cass.LocateDAO; +import org.onap.aaf.auth.dao.cass.LocateDAO.Data; +import org.onap.aaf.auth.layer.Result; +import org.onap.aaf.misc.env.APIException; + +/** + * Test the LocateDAO + * + * Utilize AbsJUCass to initialize and pre-load Cass + * + * @author Jonathan + * + */ +public class JU_LocateDAO extends AbsJUCass{ + + @Test + public void test() throws APIException, IOException { + LocateDAO pd = new LocateDAO(trans,cluster,CassAccess.KEYSPACE); + try { + LocateDAO.Data data = new LocateDAO.Data(); + data.name="org.osaaf.aaf.locateTester"; + data.hostname="mithrilcsp.sbc.com"; + data.port=19999; + data.latitude=32.780140f; + data.longitude=-96.800451f; + data.major=2; + data.minor=0; + data.patch=19; + data.pkg=23; + data.protocol="https"; + Set sp = data.subprotocol(true); + sp.add("TLS1.1"); + sp.add("TLS1.2"); + + + + // CREATE + Result rpdc = pd.create(trans,data); + assertTrue(rpdc.isOK()); + + Result> rlpd; + try { +// Bytification + ByteBuffer bb = data.bytify(); + Data bdata = new LocateDAO.Data(); + bdata.reconstitute(bb); + compare(data, bdata); + + // Validate Read with key fields in Data + rlpd = pd.read(trans,data); + assertTrue(rlpd.isOK()); + if(rlpd.isOK()) { + for(LocateDAO.Data d : rlpd.value) { + compare(data,d); + } + } + + // Validate Read by Name + rlpd = pd.readByName(trans,data.name); + assertTrue(rlpd.isOK()); + if(rlpd.isOK()) { + for(LocateDAO.Data d : rlpd.value) { + compare(data,d); + } + } + + // Modify + data.latitude = -31.0000f; + + Result rupd = pd.update(trans, data); + assertTrue(rupd.isOK()); + rlpd = pd.read(trans,data); + assertTrue(rlpd.isOK()); + if(rlpd.isOK()) { + for(LocateDAO.Data d : rlpd.value) { + compare(data,d); + } + } + + } catch (IOException e) { + e.printStackTrace(); + } finally { + // DELETE + Result rpdd = pd.delete(trans,data,true); + assertTrue(rpdd.isOK()); + rlpd = pd.read(trans, data); + assertTrue(rlpd.isOK() && rlpd.isEmpty()); + assertEquals(rlpd.value.size(),0); + } + } finally { + pd.close(trans); + } + } + + private void compare(Data a, Data b) { + assertEquals(a.name,b.name); + assertEquals(a.hostname,b.hostname); + assertEquals(a.port,b.port); + assertEquals(a.major,b.major); + assertEquals(a.minor,b.minor); + assertEquals(a.patch,b.patch); + assertEquals(a.pkg,b.pkg); + assertEquals(a.latitude,b.latitude); + assertEquals(a.longitude,b.longitude); + assertEquals(a.protocol,b.protocol); + Set spa = a.subprotocol(false); + Set spb = b.subprotocol(false); + assertEquals(spa.size(),spb.size()); + for(String s : spa) { + assertTrue(spb.contains(s)); + } + } +} diff --git a/auth/auth-cass/src/test/java/com/att/dao/aaf/test/JU_LocationContent.java b/auth/auth-cass/src/test/java/com/att/dao/aaf/test/JU_LocationContent.java new file mode 100644 index 00000000..39f096c1 --- /dev/null +++ b/auth/auth-cass/src/test/java/com/att/dao/aaf/test/JU_LocationContent.java @@ -0,0 +1,93 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package com.att.dao.aaf.test; + +import org.junit.After; +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; +import org.onap.aaf.cadi.PropAccess; +import org.onap.aaf.misc.env.APIException; +import org.onap.aaf.misc.env.Data; +import org.onap.aaf.misc.env.Data.TYPE; +import org.onap.aaf.misc.rosetta.env.RosettaDF; +import org.onap.aaf.misc.rosetta.env.RosettaEnv; + +import locate.v1_0.MgmtEndpoint; +import locate.v1_0.MgmtEndpoint.SpecialPorts; +import locate.v1_0.MgmtEndpoints; + +public class JU_LocationContent { + + @BeforeClass + public static void setUpBeforeClass() throws Exception { + } + + @AfterClass + public static void tearDownAfterClass() throws Exception { + } + + @Before + public void setUp() throws Exception { + } + + @After + public void tearDown() throws Exception { + } + + @Test + public void test() { + PropAccess access = new PropAccess(); + RosettaEnv env = new RosettaEnv(access.getProperties()); + try { + RosettaDF medf = env.newDataFactory(MgmtEndpoints.class); + medf.out(TYPE.JSON); + medf.option(Data.PRETTY); + MgmtEndpoint me = new MgmtEndpoint(); + me.setHostname("mithrilcsp.sbc.com"); + me.setLatitude(32); + me.setLongitude(-90); + me.setMajor(2); + me.setMinor(0); + me.setPatch(19); + me.setPort(3312); + me.setProtocol("http"); + me.getSubprotocol().add("TLS1.1"); + + SpecialPorts sp = new SpecialPorts(); + sp.setName("debug"); + sp.setPort(9000); + sp.setProtocol("java"); + me.getSpecialPorts().add(sp); + + MgmtEndpoints mes = new MgmtEndpoints(); + mes.getMgmtEndpoint().add(me); + System.out.println(medf.newData().load(mes).asString()); + + } catch (APIException e) { + e.printStackTrace(); + } + + } + +} diff --git a/auth/auth-cass/src/test/java/com/att/dao/aaf/test/JU_NsDAO.java b/auth/auth-cass/src/test/java/com/att/dao/aaf/test/JU_NsDAO.java new file mode 100644 index 00000000..5b313419 --- /dev/null +++ b/auth/auth-cass/src/test/java/com/att/dao/aaf/test/JU_NsDAO.java @@ -0,0 +1,187 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package com.att.dao.aaf.test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import java.io.IOException; +import java.nio.ByteBuffer; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; + +import org.junit.Test; +import org.onap.aaf.auth.dao.cass.NsDAO; +import org.onap.aaf.auth.dao.cass.NsType; +import org.onap.aaf.auth.dao.cass.NsDAO.Data; +import org.onap.aaf.auth.layer.Result; +import org.onap.aaf.misc.env.APIException; + + +public class JU_NsDAO extends AbsJUCass { + private static final String CRM = "ju_crm"; + private static final String SWM = "ju_swm"; + + @Test + public void test() throws APIException, IOException { + NsDAO nsd = new NsDAO(trans, cluster, AUTHZ); + try { + final String nsparent = "com.test"; + final String ns1 = nsparent +".ju_ns"; + final String ns2 = nsparent + ".ju_ns2"; + + Map oAttribs = new HashMap(); + oAttribs.put(SWM, "swm_data"); + oAttribs.put(CRM, "crm_data"); + Data data = new NsDAO.Data(); + data.name = ns1; + data.type = NsType.APP.type; + data.parent = nsparent; + data.attrib(true).putAll(oAttribs); + + + Result> rdrr; + + // CREATE + Result rdc = nsd.create(trans, data); + assertTrue(rdc.isOK()); + + try { +// Bytification + ByteBuffer bb = data.bytify(); + Data bdata = new NsDAO.Data(); + bdata.reconstitute(bb); + compare(data, bdata); + + // Test READ by Object + rdrr = nsd.read(trans, data); + assertTrue(rdrr.isOKhasData()); + assertEquals(rdrr.value.size(),1); + Data d = rdrr.value.get(0); + assertEquals(d.name,data.name); + assertEquals(d.type,data.type); + attribsEqual(d.attrib(false),data.attrib(false)); + attribsEqual(oAttribs,data.attrib(false)); + + // Test Read by Key + rdrr = nsd.read(trans, data.name); + assertTrue(rdrr.isOKhasData()); + assertEquals(rdrr.value.size(),1); + d = rdrr.value.get(0); + assertEquals(d.name,data.name); + assertEquals(d.type,data.type); + attribsEqual(d.attrib(false),data.attrib(false)); + attribsEqual(oAttribs,data.attrib(false)); + + // Read NS by Type + Result> rtypes = nsd.readNsByAttrib(trans, SWM); + Set types; + if(rtypes.notOK()) { + throw new IOException(rtypes.errorString()); + } else { + types = rtypes.value; + } + assertEquals(1,types.size()); + assertEquals(true,types.contains(ns1)); + + // Add second NS to test list of data returned + Data data2 = new NsDAO.Data(); + data2.name = ns2; + data2.type = 3; // app + data2.parent = nsparent; + Result rdc2 = nsd.create(trans, data2); + assertTrue(rdc2.isOK()); + + // Interrupt - test PARENT + Result> rdchildren = nsd.getChildren(trans, "com.test"); + assertTrue(rdchildren.isOKhasData()); + boolean child1 = false; + boolean child2 = false; + for(Data dchild : rdchildren.value) { + if(ns1.equals(dchild.name))child1=true; + if(ns2.equals(dchild.name))child2=true; + } + assertTrue(child1); + assertTrue(child2); + + // FINISH DATA 2 by deleting + Result rddr = nsd.delete(trans, data2, true); + assertTrue(rddr.isOK()); + + // ADD DESCRIPTION + String description = "This is my test Namespace"; + assertFalse(description.equalsIgnoreCase(data.description)); + + Result addDesc = nsd.addDescription(trans, data.name, description); + assertTrue(addDesc.isOK()); + rdrr = nsd.read(trans, data); + assertTrue(rdrr.isOKhasData()); + assertEquals(rdrr.value.size(),1); + assertEquals(rdrr.value.get(0).description,description); + + // UPDATE + String newDescription = "zz1234 Owns This Namespace Now"; + oAttribs.put("mso", "mso_data"); + data.attrib(true).put("mso", "mso_data"); + data.description = newDescription; + Result update = nsd.update(trans, data); + assertTrue(update.isOK()); + rdrr = nsd.read(trans, data); + assertTrue(rdrr.isOKhasData()); + assertEquals(rdrr.value.size(),1); + assertEquals(rdrr.value.get(0).description,newDescription); + attribsEqual(oAttribs, rdrr.value.get(0).attrib); + + + } catch (IOException e) { + e.printStackTrace(); + } finally { + // DELETE + Result rddr = nsd.delete(trans, data, true); + assertTrue(rddr.isOK()); + rdrr = nsd.read(trans, data); + assertTrue(rdrr.isOK() && rdrr.isEmpty()); + assertEquals(rdrr.value.size(),0); + } + } finally { + nsd.close(trans); + } + } + + private void compare(NsDAO.Data d, NsDAO.Data data) { + assertEquals(d.name,data.name); + assertEquals(d.type,data.type); + attribsEqual(d.attrib(false),data.attrib(false)); + attribsEqual(d.attrib(false),data.attrib(false)); + } + + private void attribsEqual(Map aa, Map ba) { + assertEquals(aa.size(),ba.size()); + for(Entry es : aa.entrySet()) { + assertEquals(es.getValue(),ba.get(es.getKey())); + } + } +} diff --git a/auth/auth-cass/src/test/java/com/att/dao/aaf/test/JU_NsType.java b/auth/auth-cass/src/test/java/com/att/dao/aaf/test/JU_NsType.java new file mode 100644 index 00000000..2644fedd --- /dev/null +++ b/auth/auth-cass/src/test/java/com/att/dao/aaf/test/JU_NsType.java @@ -0,0 +1,58 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package com.att.dao.aaf.test; + +import static org.junit.Assert.assertEquals; + +import org.junit.AfterClass; +import org.junit.Test; +import org.onap.aaf.auth.dao.cass.NsType; + +public class JU_NsType { + + @AfterClass + public static void tearDownAfterClass() throws Exception { + } + + @Test + public void test() { + NsType nt,nt2; + String[] tests = new String[] {"DOT","ROOT","COMPANY","APP","STACKED_APP","STACK"}; + for(String s : tests) { + nt = NsType.valueOf(s); + assertEquals(s,nt.name()); + + nt2 = NsType.fromString(s); + assertEquals(nt,nt2); + + int t = nt.type; + nt2 = NsType.fromType(t); + assertEquals(nt,nt2); + } + + nt = NsType.fromType(Integer.MIN_VALUE); + assertEquals(nt,NsType.UNKNOWN); + nt = NsType.fromString("Garbage"); + assertEquals(nt,NsType.UNKNOWN); + } + +} diff --git a/auth/auth-cass/src/test/java/com/att/dao/aaf/test/JU_OAuthTokenDAO.java b/auth/auth-cass/src/test/java/com/att/dao/aaf/test/JU_OAuthTokenDAO.java new file mode 100644 index 00000000..f3f91d00 --- /dev/null +++ b/auth/auth-cass/src/test/java/com/att/dao/aaf/test/JU_OAuthTokenDAO.java @@ -0,0 +1,134 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package com.att.dao.aaf.test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import java.io.IOException; +import java.nio.ByteBuffer; +import java.security.NoSuchAlgorithmException; +import java.util.Date; +import java.util.List; +import java.util.UUID; + +import org.junit.Test; +import org.onap.aaf.auth.dao.CassAccess; +import org.onap.aaf.auth.dao.cass.OAuthTokenDAO; +import org.onap.aaf.auth.dao.cass.OAuthTokenDAO.Data; +import org.onap.aaf.auth.layer.Result; +import org.onap.aaf.cadi.oauth.AAFToken; + +/** + * UserDAO unit test. + * Date: 7/19/13 + */ +public class JU_OAuthTokenDAO extends AbsJUCass { + @Test + public void test() throws IOException, NoSuchAlgorithmException { + OAuthTokenDAO adao = new OAuthTokenDAO(trans,cluster,CassAccess.KEYSPACE); + UUID uuid = UUID.randomUUID(); + try { + // Create + Data data = new OAuthTokenDAO.Data(); + data.id=AAFToken.toToken(uuid); + data.client_id="zClient"; + data.user = "xy1255@csp.att.com"; + data.active = true; + data.type=1; + data.refresh = AAFToken.toToken(UUID.randomUUID()); + data.expires=new Date(); + data.scopes(false).add("org.osaaf.aaf"); + data.scopes(false).add("org.osaaf.grid"); + data.content="{darth:\"I am your content\"}"; + data.req_ip="::1"; + +// Bytification + ByteBuffer bb = data.bytify(); + Data bdata = new OAuthTokenDAO.Data(); +// System.out.println(new String(Symm.base64noSplit.encode(bb.array()))); + bdata.reconstitute(bb); + checkData1(data, bdata); + +// DB work + adao.create(trans,data); + try { + // Validate Read with Data Object + Result> rlcd = adao.read(trans,data); + assertTrue(rlcd.isOKhasData()); + for(OAuthTokenDAO.Data d : rlcd.value) { + checkData1(data,d); + } + // Validate Read with key fields in Data + rlcd = adao.read(trans,data.id); + assertTrue(rlcd.isOKhasData()); + for(OAuthTokenDAO.Data d : rlcd.value) { + checkData1(data,d); + } + + // Validate Read by User + rlcd = adao.readByUser(trans,data.user); + assertTrue(rlcd.isOKhasData()); + for(OAuthTokenDAO.Data d : rlcd.value) { + checkData1(data,d); + } + + // Update + data.content = "{darth:\"I am your content\", luke:\"Noooooooo!\"}"; + data.active = false; + adao.update(trans,data); + rlcd = adao.read(trans,data); + assertTrue(rlcd.isOKhasData()); + for(OAuthTokenDAO.Data d : rlcd.value) { + checkData1(data,d); + } + + } finally { + // Always delete data, even if failure. + adao.delete(trans,data, true); + } + } finally { + adao.close(trans); + } + + } + + private void checkData1(Data data, Data d) { + assertEquals(data.id,d.id); + assertEquals(data.client_id,d.client_id); + assertEquals(data.user,d.user); + assertEquals(data.active,d.active); + assertEquals(data.type,d.type); + assertEquals(data.refresh,d.refresh); + assertEquals(data.expires,d.expires); + for(String s: data.scopes(false)) { + assertTrue(d.scopes(false).contains(s)); + } + for(String s: d.scopes(false)) { + assertTrue(data.scopes(false).contains(s)); + } + assertEquals(data.content,d.content); + assertEquals(data.state,d.state); + assertEquals(data.req_ip,d.req_ip); + } + +} diff --git a/auth/auth-cass/src/test/java/com/att/dao/aaf/test/JU_PermDAO.java b/auth/auth-cass/src/test/java/com/att/dao/aaf/test/JU_PermDAO.java new file mode 100644 index 00000000..0a506db1 --- /dev/null +++ b/auth/auth-cass/src/test/java/com/att/dao/aaf/test/JU_PermDAO.java @@ -0,0 +1,176 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package com.att.dao.aaf.test; + +import static junit.framework.Assert.assertEquals; +import static junit.framework.Assert.assertTrue; + +import java.io.IOException; +import java.nio.ByteBuffer; +import java.util.List; +import java.util.Set; + +import org.junit.Test; +import org.onap.aaf.auth.dao.CassAccess; +import org.onap.aaf.auth.dao.cass.PermDAO; +import org.onap.aaf.auth.dao.cass.RoleDAO; +import org.onap.aaf.auth.dao.cass.PermDAO.Data; +import org.onap.aaf.auth.layer.Result; +import org.onap.aaf.misc.env.APIException; + +/** + * Test the PermissionDAO + * + * Utilize AbsJUCass to initialize and pre-load Cass + * + * @author Jonathan + * + */ +public class JU_PermDAO extends AbsJUCass{ + + @Test + public void test() throws APIException, IOException { + PermDAO pd = new PermDAO(trans,cluster,CassAccess.KEYSPACE); + try { + PermDAO.Data data = new PermDAO.Data(); + data.ns = "com.test.ju_perm"; + data.type = "MyType"; + data.instance = "MyInstance"; + data.action = "MyAction"; + data.roles(true).add(data.ns + ".dev"); + + + + // CREATE + Result rpdc = pd.create(trans,data); + assertTrue(rpdc.isOK()); + + Result> rlpd; + try { +// Bytification + ByteBuffer bb = data.bytify(); + Data bdata = new PermDAO.Data(); + bdata.reconstitute(bb); + compare(data, bdata); + + // Validate Read with key fields in Data + if((rlpd = pd.read(trans,data)).isOK()) + for(PermDAO.Data d : rlpd.value) { + checkData1(data,d); + } + + // Validate readByName + if((rlpd = pd.readByType(trans,data.ns, data.type)).isOK()) + for(PermDAO.Data d : rlpd.value) { + checkData1(data,d); + } + + // Add Role + RoleDAO.Data role = new RoleDAO.Data(); + role.ns = data.ns; + role.name = "test"; + + Result rvpd = pd.addRole(trans, data, role.fullName()); + assertTrue(rvpd.isOK()); + // Validate Read with key fields in Data + if((rlpd = pd.read(trans,data)).isOK()) + for(PermDAO.Data d : rlpd.value) { + checkData2(data,d); + } + + // Remove Role + rvpd = pd.delRole(trans, data, role.fullName()); + assertTrue(rvpd.isOK()); + if((rlpd = pd.read(trans,data)).isOK()) + for(PermDAO.Data d : rlpd.value) { + checkData1(data,d); + } + + // Add Child + Data data2 = new Data(); + data2.ns = data.ns; + data2.type = data.type + ".2"; + data2.instance = data.instance; + data2.action = data.action; + + rpdc = pd.create(trans, data2); + assertTrue(rpdc.isOK()); + try { + rlpd = pd.readChildren(trans, data.ns,data.type); + assertTrue(rlpd.isOKhasData()); + assertEquals(rlpd.value.size(),1); + assertEquals(rlpd.value.get(0).fullType(),data2.fullType()); + } finally { + // Delete Child + pd.delete(trans, data2,true); + + } + } catch (IOException e) { + e.printStackTrace(); + } finally { + // DELETE + Result rpdd = pd.delete(trans,data,true); + assertTrue(rpdd.isOK()); + rlpd = pd.read(trans, data); + assertTrue(rlpd.isOK() && rlpd.isEmpty()); + assertEquals(rlpd.value.size(),0); + } + } finally { + pd.close(trans); + } + } + + private void compare(Data a, Data b) { + assertEquals(a.ns,b.ns); + assertEquals(a.type,b.type); + assertEquals(a.instance,b.instance); + assertEquals(a.action,b.action); + assertEquals(a.roles(false).size(),b.roles(false).size()); + for(String s: a.roles(false)) { + assertTrue(b.roles(false).contains(s)); + } + } + private void checkData1(Data data, Data d) { + assertEquals(data.ns,d.ns); + assertEquals(data.type,d.type); + assertEquals(data.instance,d.instance); + assertEquals(data.action,d.action); + + Set ss = d.roles(true); + assertEquals(1,ss.size()); + assertTrue(ss.contains(data.ns+".dev")); + } + + private void checkData2(Data data, Data d) { + assertEquals(data.ns,d.ns); + assertEquals(data.type,d.type); + assertEquals(data.instance,d.instance); + assertEquals(data.action,d.action); + + Set ss = d.roles(true); + assertEquals(2,ss.size()); + assertTrue(ss.contains(data.ns+".dev")); + assertTrue(ss.contains(data.ns+".test")); + } + + +} diff --git a/auth/auth-cass/src/test/java/com/att/dao/aaf/test/JU_RoleDAO.java b/auth/auth-cass/src/test/java/com/att/dao/aaf/test/JU_RoleDAO.java new file mode 100644 index 00000000..56875bdd --- /dev/null +++ b/auth/auth-cass/src/test/java/com/att/dao/aaf/test/JU_RoleDAO.java @@ -0,0 +1,138 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + + +package com.att.dao.aaf.test; + +import static junit.framework.Assert.assertEquals; +import static junit.framework.Assert.assertTrue; + +import java.io.IOException; +import java.nio.ByteBuffer; +import java.util.List; + +import org.junit.Test; +import org.onap.aaf.auth.dao.cass.PermDAO; +import org.onap.aaf.auth.dao.cass.RoleDAO; +import org.onap.aaf.auth.dao.cass.RoleDAO.Data; +import org.onap.aaf.auth.layer.Result; +import org.onap.aaf.misc.env.APIException; + + +public class JU_RoleDAO extends AbsJUCass { + + @Test + public void test() throws IOException, APIException { + RoleDAO rd = new RoleDAO(trans, cluster, AUTHZ); + try { + Data data = new RoleDAO.Data(); + data.ns = "com.test.ju_role"; + data.name = "role1"; + +// Bytification + ByteBuffer bb = data.bytify(); + Data bdata = new RoleDAO.Data(); + bdata.reconstitute(bb); + compare(data, bdata); + + // CREATE + Result rdc = rd.create(trans, data); + assertTrue(rdc.isOK()); + Result> rdrr; + try { + // READ + rdrr = rd.read(trans, data); + assertTrue(rdrr.isOKhasData()); + assertEquals(rdrr.value.size(),1); + Data d = rdrr.value.get(0); + assertEquals(d.perms.size(),0); + assertEquals(d.name,data.name); + assertEquals(d.ns,data.ns); + + PermDAO.Data perm = new PermDAO.Data(); + perm.ns = data.ns; + perm.type = "Perm"; + perm.instance = "perm1"; + perm.action = "write"; + + // ADD Perm + Result rdar = rd.addPerm(trans, data, perm); + assertTrue(rdar.isOK()); + rdrr = rd.read(trans, data); + assertTrue(rdrr.isOKhasData()); + assertEquals(rdrr.value.size(),1); + assertEquals(rdrr.value.get(0).perms.size(),1); + assertTrue(rdrr.value.get(0).perms.contains(perm.encode())); + + // DEL Perm + rdar = rd.delPerm(trans, data,perm); + assertTrue(rdar.isOK()); + rdrr = rd.read(trans, data); + assertTrue(rdrr.isOKhasData()); + assertEquals(rdrr.value.size(),1); + assertEquals(rdrr.value.get(0).perms.size(),0); + + // Add Child + Data data2 = new Data(); + data2.ns = data.ns; + data2.name = data.name + ".2"; + + rdc = rd.create(trans, data2); + assertTrue(rdc.isOK()); + try { + rdrr = rd.readChildren(trans, data.ns,data.name); + assertTrue(rdrr.isOKhasData()); + assertEquals(rdrr.value.size(),1); + assertEquals(rdrr.value.get(0).name,data.name + ".2"); + + rdrr = rd.readChildren(trans, data.ns,"*"); + assertTrue(rdrr.isOKhasData()); + assertEquals(rdrr.value.size(),2); + + } finally { + // Delete Child + rd.delete(trans, data2, true); + } + + } finally { + // DELETE + Result rddr = rd.delete(trans, data, true); + assertTrue(rddr.isOK()); + rdrr = rd.read(trans, data); + assertTrue(rdrr.isOK() && rdrr.isEmpty()); + assertEquals(rdrr.value.size(),0); + } + } finally { + rd.close(trans); + } + } + + private void compare(Data a, Data b) { + assertEquals(a.name,b.name); + assertEquals(a.description, b.description); + assertEquals(a.ns,b.ns); + assertEquals(a.perms(false).size(),b.perms(false).size()); + for(String p : a.perms(false)) { + assertTrue(b.perms(false).contains(p)); + } + } + +} diff --git a/auth/auth-cass/src/test/java/com/att/dao/aaf/test/NS_ChildUpdate.java b/auth/auth-cass/src/test/java/com/att/dao/aaf/test/NS_ChildUpdate.java new file mode 100644 index 00000000..8e2f78b6 --- /dev/null +++ b/auth/auth-cass/src/test/java/com/att/dao/aaf/test/NS_ChildUpdate.java @@ -0,0 +1,74 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package com.att.dao.aaf.test; + +import org.onap.aaf.auth.dao.CassAccess; +import org.onap.aaf.auth.env.AuthzEnv; + +import com.datastax.driver.core.Cluster; +import com.datastax.driver.core.ResultSet; +import com.datastax.driver.core.Row; +import com.datastax.driver.core.Session; + +public class NS_ChildUpdate { + + public static void main(String[] args) { + if(args.length < 3 ) { + System.out.println("usage: NS_ChildUpdate machine mechid (encrypted)passwd"); + } else { + try { + AuthzEnv env = new AuthzEnv(); + env.setLog4JNames("log.properties","authz","authz","audit","init","trace"); + + Cluster cluster = Cluster.builder() + .addContactPoint(args[0]) + .withCredentials(args[1],env.decrypt(args[2], false)) + .build(); + + Session session = cluster.connect(CassAccess.KEYSPACE); + try { + ResultSet result = session.execute("SELECT name,parent FROM ns"); + int count = 0; + for(Row r : result.all()) { + ++count; + String name = r.getString(0); + String parent = r.getString(1); + if(parent==null) { + int idx = name.lastIndexOf('.'); + + parent = idx>0?name.substring(0, idx):"."; + System.out.println("UPDATE " + name + " to " + parent); + session.execute("UPDATE ns SET parent='" + parent + "' WHERE name='" + name + "';"); + } + } + System.out.println("Processed " + count + " records"); + } finally { + session.close(); + cluster.close(); + } + } catch (Exception e) { + e.printStackTrace(); + } + } + } + +} diff --git a/auth/auth-cass/src/test/java/org/onap/aaf/auth/cass/hl/JU_Question.java b/auth/auth-cass/src/test/java/org/onap/aaf/auth/cass/hl/JU_Question.java new file mode 100644 index 00000000..e06a8c57 --- /dev/null +++ b/auth/auth-cass/src/test/java/org/onap/aaf/auth/cass/hl/JU_Question.java @@ -0,0 +1,509 @@ +/******************************************************************************* + * ============LICENSE_START==================================================== + * * org.onap.aaf + * * =========================================================================== + * * Copyright © 2017 AT&T Intellectual Property. All rights reserved. + * * =========================================================================== + * * 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==================================================== + * * + * * + ******************************************************************************/ +package org.onap.aaf.auth.cass.hl; + +import static junit.framework.Assert.assertEquals; +import static junit.framework.Assert.assertFalse; +import static junit.framework.Assert.assertTrue; + +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; +import org.onap.aaf.auth.dao.cass.NsDAO; +import org.onap.aaf.auth.dao.cass.PermDAO; +import org.onap.aaf.auth.dao.cass.RoleDAO; +import org.onap.aaf.auth.dao.cass.UserRoleDAO; +import org.onap.aaf.auth.dao.cass.NsDAO.Data; +import org.onap.aaf.auth.dao.hl.Question; +import org.onap.aaf.auth.dao.hl.Question.Access; +import org.onap.aaf.auth.env.AuthzTrans; +import org.onap.aaf.auth.layer.Result; +import org.onap.aaf.cadi.principal.TaggedPrincipal; +import org.onap.aaf.misc.env.Env; +import org.onap.aaf.misc.env.TimeTaken; + +import com.att.dao.aaf.test.AbsJUCass; + +public class JU_Question extends AbsJUCass { + + private static final int EXPIRES_IN = 60000000; + private static final String COM_TEST_JU = "com.test.ju_question"; + private static final String JU9999_JU_TEST_COM = "ju9999@ju.test.com"; + private static final String JU9998_JU_TEST_COM = "ju9998@ju.test.com"; + private static final String READ = "read"; + private static final int NFR_1 = 80; + private static final int NFR_2 = 4000; + private static final int ROLE_LEVEL1 = 1000; + private static final int PERM_LEVEL1 = 1000; +// private static final int PERM_LEVEL2 = 20; + private static Question q; + private static NsDAO.Data ndd; + + @BeforeClass + public static void startupBeforeClass() throws Exception { + details=false; + AuthzTrans trans = env.newTransNoAvg(); + q = new Question(trans,cluster,AUTHZ, false); + ndd = new NsDAO.Data(); + ndd.name=COM_TEST_JU; + ndd.type=3; // app + ndd.parent="com.test"; + ndd.description="Temporary Namespace for JU_Question"; + q.nsDAO.create(trans, ndd); + } + + @AfterClass + public static void endAfterClass() throws Exception { + q.nsDAO.delete(trans, ndd,false); + } +// @Test + public void mayUserRead_EmptyPerm() { + PermDAO.Data pdd = new PermDAO.Data(); + Result result = q.mayUser(trans,JU9999_JU_TEST_COM,pdd,Access.read); + assertFalse(result.isOK()); + } + +// @Test + public void mayUserRead_OnePermNotExist() { + Result result = q.mayUser(trans,JU9999_JU_TEST_COM,newPerm(0,0,READ),Access.read); + assertFalse(result.isOK()); + assertEquals("Denied - ["+ JU9999_JU_TEST_COM +"] may not read Perm [" + COM_TEST_JU + ".myPerm0|myInstance0|read]",result.errorString()); + } + +// @Test + public void mayUserRead_OnePermExistDenied() { + PermDAO.Data perm = newPerm(0,0,READ); + q.permDAO.create(trans,perm); + try { + Result result; + TimeTaken tt = trans.start("q.mayUser...", Env.SUB); + try { + result = q.mayUser(trans,JU9999_JU_TEST_COM,perm,Access.read); + } finally { + tt.done(); + assertTrue("NFR time < "+ NFR_1 + "ms",tt.millis() result; + TimeTaken tt = trans.start("q.mayUser...", Env.SUB); + try { + result = q.mayUser(trans,JU9999_JU_TEST_COM,perm,Access.read); + } finally { + tt.done(); + assertTrue("NFR time < "+ NFR_1 + "ms",tt.millis()> pres; + TimeTaken tt = trans.start("q.getPerms...", Env.SUB); + try { + pres = q.getPermsByUserFromRolesFilter(trans, JU9999_JU_TEST_COM, JU9999_JU_TEST_COM); + } finally { + tt.done(); + trans.info().log("filter_OnePermOneRleExistOK",tt); + assertTrue("NFR time < "+ NFR_1 + "ms",tt.millis() lrole = new ArrayList(); + List lur = new ArrayList(); + try { + q.permDAO.create(trans,perm); + for(int i=0;i result; + TimeTaken tt = trans.start("mayUserRead_OnePermMultiRoleExistOK", Env.SUB); + try { + result = q.mayUser(trans,JU9999_JU_TEST_COM,perm,Access.read); + } finally { + tt.done(); + env.info().log(tt,ROLE_LEVEL1,"iterations"); + assertTrue("NFR time < "+ NFR_2 + "ms",tt.millis() lperm = new ArrayList(); + try { + for(int i=0;i result; + TimeTaken tt = trans.start("mayUserRead_MultiPermOneRoleExistOK", Env.SUB); + try { + result = q.mayUser(trans,JU9999_JU_TEST_COM,lperm.get(PERM_LEVEL1-1),Access.read); + } finally { + tt.done(); + env.info().log(tt,PERM_LEVEL1,"iterations"); + assertTrue("NFR time < "+ NFR_2 + "ms",tt.millis() lperm = new ArrayList(); +// List lrole = new ArrayList(); +// List lur = new ArrayList(); +// +// try { +// RoleDAO.Data role; +// UserRoleDAO.Data ur; +// for(int i=0;i result; +// TimeTaken tt = trans.start("mayUserRead_MultiPermMultiRoleExistOK", Env.SUB); +// try { +// result = q.mayUser(trans,JU9999_JU_TEST_COM,lperm.get(ROLE_LEVEL1*PERM_LEVEL2-1),Access.read); +// } finally { +// tt.done(); +// env.info().log(tt,lperm.size(),"perms",", ",lrole.size(),"role"); +// assertTrue("NFR time < "+ NFR_2 + "ms",tt.millis() lperm = new ArrayList(); + List lrole = new ArrayList(); + List lur = new ArrayList(); + load(roleLevel, permLevel, lperm,lrole,lur); + + + Result> pres; + trans.setUser(new TaggedPrincipal() { + @Override + public String getName() { + return JU9999_JU_TEST_COM; + } + + @Override + public String tag() { + return "JUnit"; + } + + @Override + public String personalName() { + return JU9998_JU_TEST_COM; + } + }); + + try { + TimeTaken group = trans.start(" Original Security Method (1st time)", Env.SUB); + try { + TimeTaken tt = trans.start(" Get User Perms for "+JU9998_JU_TEST_COM, Env.SUB); + try { + pres = q.getPermsByUser(trans,JU9998_JU_TEST_COM,true); + } finally { + tt.done(); + env.info().log(tt," Looked up (full) getPermsByUser for",JU9998_JU_TEST_COM); + } + assertTrue(pres.isOK()); + tt = trans.start(" q.mayUser", Env.SUB); + List reduced = new ArrayList(); + + try { + for(PermDAO.Data p : pres.value) { + Result r = q.mayUser(trans,JU9999_JU_TEST_COM,p,Access.read); + if(r.isOK()) { + reduced.add(p); + } + } + } finally { + tt.done(); + env.info().log(tt," reduced" + pres.value.size(),"perms","to",reduced.size()); + // assertTrue("NFR time < "+ NFR_2 + "ms",tt.millis() lperm = new ArrayList(); + List lrole = new ArrayList(); + List lur = new ArrayList(); + load(roleLevel, permLevel, lperm,lrole,lur); + + try { + + Result> pres; + TimeTaken tt = trans.start(" mayUserRead_MultiPermMultiRoleExist_New New Filter", Env.SUB); + try { + pres = q.getPermsByUserFromRolesFilter(trans, JU9999_JU_TEST_COM, JU9998_JU_TEST_COM); + } finally { + tt.done(); + env.info().log(tt,lperm.size(),"perms",", ",lrole.size(),"role", lur.size(), "UserRoles"); +// assertTrue("NFR time < "+ NFR_2 + "ms",tt.millis() lperm , List lrole, List lur) { + RoleDAO.Data role; + UserRoleDAO.Data ur; + PermDAO.Data perm; + + int onethirdR=roleLevel/3; + int twothirdR=onethirdR*2; + int onethirdP=permLevel/3; + int twothirdP=onethirdP*2; + + for(int i=0;i lperm , List lrole, List lur) { + for(PermDAO.Data perm : lperm) { + q.permDAO.delete(trans, perm, false); + } + for(RoleDAO.Data role : lrole) { + q.roleDAO.delete(trans, role, false); + } + for(UserRoleDAO.Data ur : lur) { + q.userRoleDAO.delete(trans, ur, false); + } + + } + private PermDAO.Data newPerm(int permNum, int instNum, String action, RoleDAO.Data ... grant) { + PermDAO.Data pdd = new PermDAO.Data(); + pdd.ns=COM_TEST_JU; + pdd.type="myPerm"+permNum; + pdd.instance="myInstance"+instNum; + pdd.action=action; + for(RoleDAO.Data r : grant) { + pdd.roles(true).add(r.fullName()); + r.perms(true).add(pdd.encode()); + } + return pdd; + } + + private RoleDAO.Data newRole(int roleNum, PermDAO.Data ... grant) { + RoleDAO.Data rdd = new RoleDAO.Data(); + rdd.ns = COM_TEST_JU+roleNum; + rdd.name = "myRole"+roleNum; + for(PermDAO.Data p : grant) { + rdd.perms(true).add(p.encode()); + p.roles(true).add(rdd.fullName()); + } + return rdd; + } + + private UserRoleDAO.Data newUserRole(RoleDAO.Data role,String user, long offset) { + UserRoleDAO.Data urd = new UserRoleDAO.Data(); + urd.user=user; + urd.role(role); + urd.expires=new Date(System.currentTimeMillis()+offset); + return urd; + } + + +} diff --git a/auth/auth-cass/src/test/java/org/onap/aaf/auth/cass/hl/JU_Question2.java b/auth/auth-cass/src/test/java/org/onap/aaf/auth/cass/hl/JU_Question2.java new file mode 100644 index 00000000..bfb6fd4e --- /dev/null +++ b/auth/auth-cass/src/test/java/org/onap/aaf/auth/cass/hl/JU_Question2.java @@ -0,0 +1,73 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.cass.hl; + +import java.io.IOException; + +import org.junit.After; +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; +import org.onap.aaf.auth.dao.hl.Question; + +public class JU_Question2 { + + @BeforeClass + public static void setUpBeforeClass() throws Exception { + } + + @AfterClass + public static void tearDownAfterClass() throws Exception { + } + + @Before + public void setUp() throws Exception { + } + + @After + public void tearDown() throws Exception { + } + + @Test + public void test() throws IOException { + String s,u; + System.out.println((s="com") + '=' + (u=Question.toUnique(s))); + System.out.println(u+'='+(Question.fromUnique(u))); + System.out.println((s="org.osaaf.cdp.Tenant32_what-a-joy") + '=' + (u=Question.toUnique(s))); + System.out.println(u+'='+(Question.fromUnique(u))); + System.out.println((s="org.osaaf.cdp") + '=' + (u=Question.toUnique(s))); + System.out.println(u+'='+(Question.fromUnique(u))); + +// Assert.assertSame(s="com", Question.toUnique(s)); +// Assert.assertSame(s="", Question.toUnique(s)); +// Assert.assertSame(s="com.aa", Question.toUnique(s)); +// Assert.assertNotSame(s="com.Aa", Question.toUnique(s)); +// Assert.assertEquals("com.aa", Question.toUnique(s)); +// Assert.assertNotSame(s="com.Aa.1", Question.toUnique(s)); +// Assert.assertEquals("com.aa.1", Question.toUnique(s)); +// Assert.assertNotSame(s="com.Aa.1-3", Question.toUnique(s)); +// Assert.assertEquals("com.aa.13", Question.toUnique(s)); +// Assert.assertEquals("com.aa.13", Question.toUnique("com.aA.1_3")); + } + +} diff --git a/auth/auth-cass/src/test/java/org/onap/aaf/auth/dao/JU_Cached.java b/auth/auth-cass/src/test/java/org/onap/aaf/auth/dao/JU_Cached.java new file mode 100644 index 00000000..22f9a6f7 --- /dev/null +++ b/auth/auth-cass/src/test/java/org/onap/aaf/auth/dao/JU_Cached.java @@ -0,0 +1,124 @@ +/******************************************************************************* + * ============LICENSE_START==================================================== + * * org.onap.aaf + * * =========================================================================== + * * Copyright © 2017 AT&T Intellectual Property. All rights reserved. + * * =========================================================================== + * * 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==================================================== + * * + * * + ******************************************************************************/ +package org.onap.aaf.auth.dao; + +import static org.junit.Assert.*; + +import java.util.Date; +import java.util.List; +import java.util.Map; +import java.util.Timer; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.onap.aaf.auth.cache.Cache; +import org.onap.aaf.auth.cache.Cache.Dated; +import org.onap.aaf.auth.dao.CIDAO; +import org.onap.aaf.auth.dao.Cached; +import org.onap.aaf.auth.dao.Cached.Getter; +import org.onap.aaf.auth.env.AuthzEnv; +import org.onap.aaf.auth.env.AuthzTrans; +import org.onap.aaf.auth.layer.Result; +import org.onap.aaf.misc.env.Trans; +import org.powermock.modules.junit4.PowerMockRunner; + +@RunWith(PowerMockRunner.class) +public class JU_Cached { + Cached cached; + @Mock + CIDAO ciDaoMock; + @Mock + AuthzEnv authzEnvMock; + @Mock + CIDAO cidaoATMock; + + String name = "nameString"; + + @Before + public void setUp(){ + cached = new Cached(ciDaoMock, name, (int)0, 30000L); + } + + @Test(expected=ArithmeticException.class) + public void testCachedIdx(){ + int Result = cached.cacheIdx("1234567890"); + } + + @Test(expected=ArithmeticException.class) + public void testInvalidate(){ + int Res = cached.invalidate(name); + } + + @SuppressWarnings("static-access") + @Test + public void testStopTimer(){ + cached.stopTimer(); + assertTrue(true); + } + + @SuppressWarnings("static-access") + @Test + public void testStartRefresh(){ + cached.startRefresh(authzEnvMock, cidaoATMock); + assertTrue(true); + } +// @Mock +// Trans transMock; +// @Mock +// Getter getterMock; +// +// @Test +// public void testGet(){ +// cached.get(transMock, name, getterMock); +// fail("not implemented"); +// } +// +// @SuppressWarnings("unchecked") +// public Result> get(TRANS trans, String key, Getter getter) { +// List ld = null; +// Result> rld = null; +// +// int cacheIdx = cacheIdx(key); +// Map map = ((Map)cache[cacheIdx]); +// +// // Check for saved element in cache +// Dated cached = map.get(key); +// // Note: These Segment Timestamps are kept up to date with DB +// Date dbStamp = info.get(trans, name,cacheIdx); +// +// // Check for cache Entry and whether it is still good (a good Cache Entry is same or after DBEntry, so we use "before" syntax) +// if(cached!=null && dbStamp.before(cached.timestamp)) { +// ld = (List)cached.data; +// rld = Result.ok(ld); +// } else { +// rld = getter.get(); +// if(rld.isOK()) { // only store valid lists +// map.put(key, new Dated(rld.value)); // successful item found gets put in cache +//// } else if(rld.status == Result.ERR_Backend){ +//// map.remove(key); +// } +// } +// return rld; +// } +} diff --git a/auth/auth-cass/src/test/java/org/onap/aaf/auth/dao/JU_CachedDAO.java b/auth/auth-cass/src/test/java/org/onap/aaf/auth/dao/JU_CachedDAO.java new file mode 100644 index 00000000..14612a1f --- /dev/null +++ b/auth/auth-cass/src/test/java/org/onap/aaf/auth/dao/JU_CachedDAO.java @@ -0,0 +1,64 @@ +/******************************************************************************* + * ============LICENSE_START==================================================== + * * org.onap.aaf + * * =========================================================================== + * * Copyright © 2017 AT&T Intellectual Property. All rights reserved. + * * =========================================================================== + * * 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==================================================== + * * + * * + ******************************************************************************/ +package org.onap.aaf.auth.dao; + +import static org.junit.Assert.*; + +import java.util.ArrayList; +import java.util.List; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.onap.aaf.auth.dao.CIDAO; +import org.onap.aaf.auth.dao.CachedDAO; +import org.onap.aaf.auth.dao.DAO; +import org.onap.aaf.misc.env.Trans; +import org.powermock.modules.junit4.PowerMockRunner; + +@RunWith(PowerMockRunner.class) +public class JU_CachedDAO { + CachedDAO cachedDAO; + @Mock + DAO daoMock; + @Mock + CIDAO ciDAOMock; + int segsize=1; + Object[ ] objs = new Object[2]; + + @Before + public void setUp(){ + objs[0] = "helo"; + objs[1] = "polo"; + cachedDAO = new CachedDAO(daoMock, ciDAOMock, segsize, segsize); + } + + @Test + public void testKeyFromObjs(){ + String result = cachedDAO.keyFromObjs(objs); + System.out.println("value of resut " +result); + assertTrue(true); + } + +} diff --git a/auth/auth-cass/src/test/java/org/onap/aaf/auth/dao/JU_CassAccess.java b/auth/auth-cass/src/test/java/org/onap/aaf/auth/dao/JU_CassAccess.java new file mode 100644 index 00000000..c73371e9 --- /dev/null +++ b/auth/auth-cass/src/test/java/org/onap/aaf/auth/dao/JU_CassAccess.java @@ -0,0 +1,73 @@ +/******************************************************************************* + * ============LICENSE_START==================================================== + * * org.onap.aaf + * * =========================================================================== + * * Copyright © 2017 AT&T Intellectual Property. All rights reserved. + * * =========================================================================== + * * 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==================================================== + * * + * * + ******************************************************************************/ +package org.onap.aaf.auth.dao; + +import static org.junit.Assert.*; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.onap.aaf.auth.dao.CassAccess; +import org.onap.aaf.misc.env.APIException; +import org.onap.aaf.misc.env.Env; +import org.powermock.modules.junit4.PowerMockRunner; + +//import org.onap.aaf.auth.dao.CassAccess.Resettable; +import com.datastax.driver.core.Cluster.Builder; + +@RunWith(PowerMockRunner.class) +public class JU_CassAccess { + CassAccess cassAccess; + + public static final String KEYSPACE = "authz"; + public static final String CASSANDRA_CLUSTERS = "cassandra.clusters"; + public static final String CASSANDRA_CLUSTERS_PORT = "cassandra.clusters.port"; + public static final String CASSANDRA_CLUSTERS_USER_NAME = "cassandra.clusters.user"; + public static final String CASSANDRA_CLUSTERS_PASSWORD = "cassandra.clusters.password"; + public static final String CASSANDRA_RESET_EXCEPTIONS = "cassandra.reset.exceptions"; + public static final String LATITUDE = "LATITUDE"; + public static final String LONGITUDE = "LONGITUDE"; + //private static final List resetExceptions = new ArrayList(); + public static final String ERR_ACCESS_MSG = "Accessing Backend"; + private static Builder cb = null; + @Mock + Env envMock; + String prefix=null; + + @Before + public void setUp(){ + cassAccess = new CassAccess(); + } + + + @Test(expected=APIException.class) + public void testCluster() throws APIException, IOException { + cassAccess.cluster(envMock, prefix); + + } + +} diff --git a/auth/auth-cass/src/test/java/org/onap/aaf/auth/dao/JU_CassDAOImpl.java b/auth/auth-cass/src/test/java/org/onap/aaf/auth/dao/JU_CassDAOImpl.java new file mode 100644 index 00000000..d06e38f7 --- /dev/null +++ b/auth/auth-cass/src/test/java/org/onap/aaf/auth/dao/JU_CassDAOImpl.java @@ -0,0 +1,96 @@ +/******************************************************************************* + * ============LICENSE_START==================================================== + * * org.onap.aaf + * * =========================================================================== + * * Copyright © 2017 AT&T Intellectual Property. All rights reserved. + * * =========================================================================== + * * 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==================================================== + * * + * * + ******************************************************************************/ +package org.onap.aaf.auth.dao; + +import static org.junit.Assert.*; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.onap.aaf.auth.dao.CassDAOImpl; +import org.onap.aaf.auth.dao.Loader; +import org.onap.aaf.auth.env.AuthzTrans; +import org.onap.aaf.misc.env.Data; +import org.onap.aaf.misc.env.Trans; +import org.onap.aaf.misc.env.TransStore; +import org.powermock.api.mockito.PowerMockito; +import org.powermock.modules.junit4.PowerMockRunner; + +import com.datastax.driver.core.Cluster; +import com.datastax.driver.core.ConsistencyLevel; + +@RunWith(PowerMockRunner.class) +public class JU_CassDAOImpl { + +public static final String CASS_READ_CONSISTENCY="cassandra.readConsistency"; +public static final String CASS_WRITE_CONSISTENCY="cassandra.writeConsistency"; + +CassDAOImpl cassDAOImpl; + + +@Mock +TransStore transStoreMock; +@SuppressWarnings("rawtypes") +Class dcMock; +@SuppressWarnings("rawtypes") +Loader loaderMock; +Cluster clusterMock; +Class classDataMock; +ConsistencyLevel consistencyLevelMock; +Trans transMock; + +@Mock +AuthzTrans authzTransMock; + + + + @SuppressWarnings({ "rawtypes", "unchecked" }) + @Before + public void setUp() + { + String name = "name"; + String keySpace = "keySpace"; + String table = "table"; + cassDAOImpl = new CassDAOImpl(transStoreMock, name, clusterMock, keySpace, classDataMock, table, consistencyLevelMock, consistencyLevelMock); + } + + //TODO: Gabe [JUnit] Visibility issue + @Test + public void testReadConsistency() { + String table = "users"; + PowerMockito.when(authzTransMock.getProperty(CASS_READ_CONSISTENCY+'.'+table)).thenReturn("TWO"); + ConsistencyLevel consistencyLevel = cassDAOImpl.readConsistency(authzTransMock, table); + System.out.println("Consistency level" + consistencyLevel.name()); + assertEquals("TWO", consistencyLevel.name()); + } + + @Test + public void testWriteConsistency() { + String table = "users"; + PowerMockito.when(authzTransMock.getProperty(CASS_WRITE_CONSISTENCY+'.'+table)).thenReturn(null); + ConsistencyLevel consistencyLevel = cassDAOImpl.writeConsistency(authzTransMock, table); + System.out.println("Consistency level" + consistencyLevel.name()); + assertEquals("ONE", consistencyLevel.name()); + } + +} diff --git a/auth/auth-cass/src/test/java/org/onap/aaf/auth/dao/JU_DAOException.java b/auth/auth-cass/src/test/java/org/onap/aaf/auth/dao/JU_DAOException.java new file mode 100644 index 00000000..8cfb8520 --- /dev/null +++ b/auth/auth-cass/src/test/java/org/onap/aaf/auth/dao/JU_DAOException.java @@ -0,0 +1,49 @@ +/******************************************************************************* + * ============LICENSE_START==================================================== + * * org.onap.aaf + * * =========================================================================== + * * Copyright © 2017 AT&T Intellectual Property. All rights reserved. + * * =========================================================================== + * * 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==================================================== + * * + * * + ******************************************************************************/ +package org.onap.aaf.auth.dao; + +import static org.junit.Assert.*; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.onap.aaf.auth.dao.DAOException; +import org.powermock.api.mockito.PowerMockito; +import org.powermock.modules.junit4.PowerMockRunner; + +@RunWith(PowerMockRunner.class) +public class JU_DAOException { +DAOException daoException; + + //DAOException daoException = new DAOException(); + String message = "message"; + Throwable cause; + @Before + public void setUp(){ + daoException = new DAOException(); + } + + @Test + public void test(){ + assertTrue(true); + } +} diff --git a/auth/auth-cass/src/test/java/org/onap/aaf/auth/dao/aaf/test/AbsJUCass.java b/auth/auth-cass/src/test/java/org/onap/aaf/auth/dao/aaf/test/AbsJUCass.java new file mode 100644 index 00000000..3064de55 --- /dev/null +++ b/auth/auth-cass/src/test/java/org/onap/aaf/auth/dao/aaf/test/AbsJUCass.java @@ -0,0 +1,200 @@ +/******************************************************************************* + * ============LICENSE_START==================================================== + * * org.onap.aaf + * * =========================================================================== + * * Copyright © 2017 AT&T Intellectual Property. All rights reserved. + * * =========================================================================== + * * 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==================================================== + * * + * * + ******************************************************************************/ +package org.onap.aaf.auth.dao.aaf.test; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; +import java.security.NoSuchAlgorithmException; +import java.util.Properties; + +import org.junit.After; +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.BeforeClass; +import org.onap.aaf.auth.dao.CassAccess; +import org.onap.aaf.auth.dao.CassDAOImpl; +import org.onap.aaf.auth.env.AuthzEnv; +import org.onap.aaf.auth.env.AuthzTrans; +import org.onap.aaf.cadi.Hash; +import org.onap.aaf.cadi.Symm; +import org.onap.aaf.misc.env.APIException; +import org.onap.aaf.misc.env.Env; +import org.onap.aaf.misc.env.Trans.Metric; + +import com.datastax.driver.core.Cluster; + +import junit.framework.Assert; + +/** + * Do Setup of Cassandra for Cassandra JUnit Testing + * + * + */ +public class AbsJUCass { + protected static final String AUTHZ = "authz"; + protected static Cluster cluster; + protected static AuthzEnv env; + protected static int iterations = 0; + protected static float totals=0.0f; + protected static float remote = 0.0f; + protected static float json = 0.0f; + protected static AuthzTrans trans; + protected static boolean details = true; + + @BeforeClass + public static void startup() throws APIException, IOException { + synchronized(AUTHZ) { + if(env==null) { + final String resource = "cadi.properties"; + File f = new File("etc" + resource); + InputStream is=null; + Properties props = new Properties(); + try { + if(f.exists()) { + is = new FileInputStream(f); + } else { + URL rsrc = ClassLoader.getSystemResource(resource); + is = rsrc.openStream(); + } + props.load(is); + } finally { + if(is==null) { + env= new AuthzEnv(); + Assert.fail(resource + " must exist in etc dir, or in Classpath"); + } + is.close(); + } + env = new AuthzEnv(props); + } + } + cluster = CassAccess.cluster(env,"LOCAL"); + + env.info().log("Connecting to Cluster"); + try { + cluster.connect(AUTHZ); + } catch(Exception e) { + cluster=null; + env.error().log(e); + Assert.fail("Not able to connect to DB: " + e.getLocalizedMessage()); + } + env.info().log("Connected"); + + // Load special data here + + // WebPhone + env.setProperty("java.naming.provider.url","ldap://ldap.webphone.att.com:389"); + env.setProperty("com.sun.jndi.ldap.connect.pool","true"); + + iterations = 0; + + } + + @AfterClass + public static void shutdown() { + if(cluster!=null) { + cluster.close(); + cluster = null; + } + } + + @Before + public void newTrans() { + trans = env.newTrans(); + + trans.setProperty(CassDAOImpl.USER_NAME, System.getProperty("user.name")); + } + + @After + public void auditTrail() { + if(totals==0) { // "updateTotals()" was not called... just do one Trans + StringBuilder sb = new StringBuilder(); + Metric metric = trans.auditTrail(4, sb, Env.JSON, Env.REMOTE); + if(details) { + env.info().log( + sb, + "Total time:", + totals += metric.total, + "JSON time: ", + metric.buckets[0], + "REMOTE time: ", + metric.buckets[1] + ); + } else { + totals += metric.total; + } + } + } + + protected void updateTotals() { + Metric metric = trans.auditTrail(0, null, Env.JSON, Env.REMOTE); + totals+=metric.total; + json +=metric.buckets[0]; + remote+=metric.buckets[1]; + } + + + @AfterClass + public static void print() { + float transTime; + if(iterations==0) { + transTime=totals; + } else { + transTime=totals/iterations; + } + env.info().log( + "Total time:", + totals, + "JSON time:", + json, + "REMOTE time:", + remote, + "Iterations:", + iterations, + "Transaction time:", + transTime + ); + } + + /** + * Take a User/Pass and turn into an MD5 Hashed BasicAuth + * + * @param user + * @param pass + * @return + * @throws IOException + * @throws NoSuchAlgorithmException + */ + //TODO: Gabe [JUnit] Issue + public static byte[] userPassToBytes(String user, String pass) + throws IOException, NoSuchAlgorithmException { + // Take the form of BasicAuth, so as to allow any character in Password + // (this is an issue in 1.0) + // Also, it makes it quicker to evaluate Basic Auth direct questions + String ba = Symm.base64url.encode(user + ':' + pass); + // Take MD5 Hash, so that data in DB can't be reversed out. + return Hash.hashMD5(ba.getBytes()); + } + +} diff --git a/auth/auth-cass/src/test/java/org/onap/aaf/auth/dao/aaf/test/JU_ApprovalDAO.java b/auth/auth-cass/src/test/java/org/onap/aaf/auth/dao/aaf/test/JU_ApprovalDAO.java new file mode 100644 index 00000000..13a13edf --- /dev/null +++ b/auth/auth-cass/src/test/java/org/onap/aaf/auth/dao/aaf/test/JU_ApprovalDAO.java @@ -0,0 +1,146 @@ +/******************************************************************************* + * ============LICENSE_START==================================================== + * * org.onap.aaf + * * =========================================================================== + * * Copyright © 2017 AT&T Intellectual Property. All rights reserved. + * * =========================================================================== + * * 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==================================================== + * * + * * + ******************************************************************************/ +package org.onap.aaf.auth.dao.aaf.test; + + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotSame; +import static org.junit.Assert.assertTrue; + +import java.util.Date; +import java.util.List; +import java.util.UUID; + +import org.junit.Test; +import org.onap.aaf.auth.dao.cass.ApprovalDAO; +import org.onap.aaf.auth.dao.cass.ApprovalDAO.Data; +import org.onap.aaf.auth.layer.Result; + +public class JU_ApprovalDAO extends AbsJUCass { + @Test + public void testCRUD() throws Exception { + ApprovalDAO rrDAO = new ApprovalDAO(trans, cluster, AUTHZ); + ApprovalDAO.Data data = new ApprovalDAO.Data(); + + data.ticket = UUID.randomUUID(); // normally, read from Future object + data.user = "testid@test.com"; + data.approver = "mySuper@att.com"; + data.type = "supervisor"; + data.status = "pending"; + data.operation = "C"; + data.updated = new Date(); + + try { + // Test create + rrDAO.create(trans, data); + + // Test Read by Ticket + Result> rlad; + rlad = rrDAO.readByTicket(trans, data.ticket); + assertTrue(rlad.isOK()); + assertEquals(1,rlad.value.size()); + compare(data,rlad.value.get(0)); + + // Hold onto original ID for deletion, and read tests + UUID id = rlad.value.get(0).id; + + try { + // Test Read by User + rlad = rrDAO.readByUser(trans, data.user); + assertTrue(rlad.isOKhasData()); + boolean ok = false; + for(ApprovalDAO.Data a : rlad.value) { + if(a.id.equals(id)) { + ok = true; + compare(data,a); + } + } + assertTrue(ok); + + // Test Read by Approver + rlad = rrDAO.readByApprover(trans, data.approver); + assertTrue(rlad.isOKhasData()); + ok = false; + for(ApprovalDAO.Data a : rlad.value) { + if(a.id.equals(id)) { + ok = true; + compare(data,a); + } + } + assertTrue(ok); + + // Test Read by ID + rlad = rrDAO.read(trans, id); + assertTrue(rlad.isOKhasData()); + ok = false; + for(ApprovalDAO.Data a : rlad.value) { + if(a.id.equals(id)) { + ok = true; + compare(data,a); + } + } + assertTrue(ok); + + // Test Update + data.status = "approved"; + data.id = id; + assertTrue(rrDAO.update(trans, data).isOK()); + + rlad = rrDAO.read(trans, id); + assertTrue(rlad.isOKhasData()); + ok = false; + for(ApprovalDAO.Data a : rlad.value) { + if(a.id.equals(id)) { + ok = true; + compare(data,a); + } + } + assertTrue(ok); + + } finally { + // Delete + data.id = id; + rrDAO.delete(trans, data, true); + rlad = rrDAO.read(trans, id); + assertTrue(rlad.isOK()); + assertTrue(rlad.isEmpty()); + } + + } finally { + rrDAO.close(trans); + } + } + + private void compare(Data d1, Data d2) { + assertNotSame(d1.id,d2.id); + assertEquals(d1.ticket,d2.ticket); + assertEquals(d1.user,d2.user); + assertEquals(d1.approver,d2.approver); + assertEquals(d1.type,d2.type); + assertEquals(d1.status,d2.status); + assertEquals(d1.operation,d2.operation); + assertNotSame(d1.updated,d2.updated); + } + + + +} diff --git a/auth/auth-cass/src/test/java/org/onap/aaf/auth/dao/aaf/test/JU_ArtiDAO.java b/auth/auth-cass/src/test/java/org/onap/aaf/auth/dao/aaf/test/JU_ArtiDAO.java new file mode 100644 index 00000000..f095e32f --- /dev/null +++ b/auth/auth-cass/src/test/java/org/onap/aaf/auth/dao/aaf/test/JU_ArtiDAO.java @@ -0,0 +1,136 @@ +/******************************************************************************* + * ============LICENSE_START==================================================== + * * org.onap.aaf + * * =========================================================================== + * * Copyright © 2017 AT&T Intellectual Property. All rights reserved. + * * =========================================================================== + * * 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==================================================== + * * + * * + ******************************************************************************/ +package org.onap.aaf.auth.dao.aaf.test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import java.io.IOException; +import java.nio.ByteBuffer; +import java.security.NoSuchAlgorithmException; +import java.util.Date; +import java.util.List; + +import org.junit.Test; +import org.onap.aaf.auth.dao.cass.ArtiDAO; +import org.onap.aaf.auth.dao.cass.ArtiDAO.Data; +import org.onap.aaf.auth.layer.Result; + +/** + * UserDAO unit test. + * User: tp007s + * Date: 7/19/13 + */ +public class JU_ArtiDAO extends AbsJUCass { + @Test + public void test() throws IOException, NoSuchAlgorithmException { + ArtiDAO adao = new ArtiDAO(trans,cluster,"authz"); + try { + // Create + ArtiDAO.Data data = new ArtiDAO.Data(); + data.mechid="m55555@perturbed.att.com"; + data.machine="perturbed1232.att.com"; + data.type(false).add("file"); + data.type(false).add("jks"); + data.sponsor="Fred Flintstone"; + data.ca="devl"; + data.dir="/opt/app/aft/keys"; + data.ns="kumquat"; + data.os_user="aft"; + data.notify="email:myname@bogus.email.com"; + data.expires=new Date(); + +// Bytification + ByteBuffer bb = data.bytify(); + Data bdata = new ArtiDAO.Data(); + bdata.reconstitute(bb); + checkData1(data, bdata); + + +// DB work + adao.create(trans,data); + try { + // Validate Read with key fields in Data + Result> rlcd = adao.read(trans,data); + assertTrue(rlcd.isOKhasData()); + for(ArtiDAO.Data d : rlcd.value) { + checkData1(data,d); + } + + // Validate Read with key fields in Data + rlcd = adao.read(trans,data.mechid, data.machine); + assertTrue(rlcd.isOKhasData()); + for(ArtiDAO.Data d : rlcd.value) { + checkData1(data,d); + } + + // By Machine + rlcd = adao.readByMachine(trans,data.machine); + assertTrue(rlcd.isOKhasData()); + for(ArtiDAO.Data d : rlcd.value) { + checkData1(data,d); + } + + // By MechID + rlcd = adao.readByMechID(trans,data.mechid); + assertTrue(rlcd.isOKhasData()); + for(ArtiDAO.Data d : rlcd.value) { + checkData1(data,d); + } + + // Update + data.sponsor = "Wilma Flintstone"; + adao.update(trans,data); + rlcd = adao.read(trans,data); + assertTrue(rlcd.isOKhasData()); + for(ArtiDAO.Data d : rlcd.value) { + checkData1(data,d); + } + + } finally { + // Always delete data, even if failure. + adao.delete(trans,data, true); + } + } finally { + adao.close(trans); + } + + + } + + private void checkData1(Data data, Data d) { + assertEquals(data.mechid,d.mechid); + assertEquals(data.machine,d.machine); + assertEquals(data.type(false).size(),d.type(false).size()); + for(String s: data.type(false)) { + assertTrue(d.type(false).contains(s)); + } + assertEquals(data.sponsor,d.sponsor); + assertEquals(data.ca,d.ca); + assertEquals(data.dir,d.dir); + assertEquals(data.ns,d.ns); + assertEquals(data.os_user,d.os_user); + assertEquals(data.notify,d.notify); + assertEquals(data.expires,d.expires); + } + +} diff --git a/auth/auth-cass/src/test/java/org/onap/aaf/auth/dao/aaf/test/JU_Bytification.java b/auth/auth-cass/src/test/java/org/onap/aaf/auth/dao/aaf/test/JU_Bytification.java new file mode 100644 index 00000000..e316ac7e --- /dev/null +++ b/auth/auth-cass/src/test/java/org/onap/aaf/auth/dao/aaf/test/JU_Bytification.java @@ -0,0 +1,265 @@ +/******************************************************************************* + * ============LICENSE_START==================================================== + * * org.onap.aaf + * * =========================================================================== + * * Copyright © 2017 AT&T Intellectual Property. All rights reserved. + * * =========================================================================== + * * 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==================================================== + * * + * * + ******************************************************************************/ +package org.onap.aaf.auth.dao.aaf.test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import java.io.IOException; +import java.nio.ByteBuffer; +import java.util.Date; + +import org.junit.Test; +import org.onap.aaf.auth.dao.cass.CredDAO; +import org.onap.aaf.auth.dao.cass.NsDAO; +import org.onap.aaf.auth.dao.cass.NsType; +import org.onap.aaf.auth.dao.cass.PermDAO; +import org.onap.aaf.auth.dao.cass.RoleDAO; +import org.onap.aaf.auth.dao.cass.UserRoleDAO; + +public class JU_Bytification { + + @Test + public void testNS() throws IOException { + + // Normal + NsDAO.Data ns = new NsDAO.Data(); + ns.name = "org.osaaf."; + ns.type = NsType.APP.type; + + ByteBuffer bb = ns.bytify(); + + NsDAO.Data nsr = new NsDAO.Data(); + nsr.reconstitute(bb); + check(ns,nsr); + + // Empty admin +// ns.admin(true).clear(); + bb = ns.bytify(); + nsr = new NsDAO.Data(); + nsr.reconstitute(bb); + check(ns,nsr); + + // Empty responsible +// ns.responsible(true).clear(); + bb = ns.bytify(); + nsr = new NsDAO.Data(); + nsr.reconstitute(bb); + check(ns,nsr); + + bb = ns.bytify(); + nsr = new NsDAO.Data(); + nsr.reconstitute(bb); + check(ns,nsr); + } + + private void check(NsDAO.Data a, NsDAO.Data b) { + assertEquals(a.name,b.name); + assertEquals(a.type,b.type); +// assertEquals(a.admin.size(),b.admin.size()); + +// for(String s: a.admin) { +// assertTrue(b.admin.contains(s)); +// } +// +// assertEquals(a.responsible.size(),b.responsible.size()); +// for(String s: a.responsible) { +// assertTrue(b.responsible.contains(s)); +// } + } + + @Test + public void testRole() throws IOException { + RoleDAO.Data rd1 = new RoleDAO.Data(); + rd1.ns = "org.osaaf."; + rd1.name = "my.role"; + rd1.perms(true).add("org.osaaf..my.Perm|myInstance|myAction"); + rd1.perms(true).add("org.osaaf..my.Perm|myInstance|myAction2"); + + // Normal + ByteBuffer bb = rd1.bytify(); + RoleDAO.Data rd2 = new RoleDAO.Data(); + rd2.reconstitute(bb); + check(rd1,rd2); + + // Overshoot Buffer + StringBuilder sb = new StringBuilder(300); + sb.append("role|instance|veryLongAction..."); + for(int i=0;i<280;++i) { + sb.append('a'); + } + rd1.perms(true).add(sb.toString()); + bb = rd1.bytify(); + rd2 = new RoleDAO.Data(); + rd2.reconstitute(bb); + check(rd1,rd2); + + // No Perms + rd1.perms.clear(); + + bb = rd1.bytify(); + rd2 = new RoleDAO.Data(); + rd2.reconstitute(bb); + check(rd1,rd2); + + // 1000 Perms + for(int i=0;i<1000;++i) { + rd1.perms(true).add("com|inst|action"+ i); + } + + bb = rd1.bytify(); + rd2 = new RoleDAO.Data(); + rd2.reconstitute(bb); + check(rd1,rd2); + + } + + private void check(RoleDAO.Data a, RoleDAO.Data b) { + assertEquals(a.ns,b.ns); + assertEquals(a.name,b.name); + + assertEquals(a.perms.size(),b.perms.size()); + for(String s: a.perms) { + assertTrue(b.perms.contains(s)); + } + } + + @Test + public void testPerm() throws IOException { + PermDAO.Data pd1 = new PermDAO.Data(); + pd1.ns = "org.osaaf."; + pd1.type = "my.perm"; + pd1.instance = "instance"; + pd1.action = "read"; + pd1.roles(true).add("org.osaaf..my.Role"); + pd1.roles(true).add("org.osaaf..my.Role2"); + + // Normal + ByteBuffer bb = pd1.bytify(); + PermDAO.Data rd2 = new PermDAO.Data(); + rd2.reconstitute(bb); + check(pd1,rd2); + + // No Perms + pd1.roles.clear(); + + bb = pd1.bytify(); + rd2 = new PermDAO.Data(); + rd2.reconstitute(bb); + check(pd1,rd2); + + // 1000 Perms + for(int i=0;i<1000;++i) { + pd1.roles(true).add("org.osaaf..my.Role"+ i); + } + + bb = pd1.bytify(); + rd2 = new PermDAO.Data(); + rd2.reconstitute(bb); + check(pd1,rd2); + + } + + private void check(PermDAO.Data a, PermDAO.Data b) { + assertEquals(a.ns,b.ns); + assertEquals(a.type,b.type); + assertEquals(a.instance,b.instance); + assertEquals(a.action,b.action); + + assertEquals(a.roles.size(),b.roles.size()); + for(String s: a.roles) { + assertTrue(b.roles.contains(s)); + } + } + + @Test + public void testUserRole() throws IOException { + UserRoleDAO.Data urd1 = new UserRoleDAO.Data(); + urd1.user = "myname@abc.att.com"; + urd1.role("org.osaaf.","my.role"); + urd1.expires = new Date(); + + // Normal + ByteBuffer bb = urd1.bytify(); + UserRoleDAO.Data urd2 = new UserRoleDAO.Data(); + urd2.reconstitute(bb); + check(urd1,urd2); + + // A null + urd1.expires = null; + urd1.role = null; + + bb = urd1.bytify(); + urd2 = new UserRoleDAO.Data(); + urd2.reconstitute(bb); + check(urd1,urd2); + } + + private void check(UserRoleDAO.Data a, UserRoleDAO.Data b) { + assertEquals(a.user,b.user); + assertEquals(a.role,b.role); + assertEquals(a.expires,b.expires); + } + + + @Test + public void testCred() throws IOException { + CredDAO.Data cd = new CredDAO.Data(); + cd.id = "m55555@abc.att.com"; + cd.ns = "org.osaaf.abc"; + cd.type = 2; + cd.cred = ByteBuffer.wrap(new byte[]{1,34,5,3,25,0,2,5,3,4}); + cd.expires = new Date(); + + // Normal + ByteBuffer bb = cd.bytify(); + CredDAO.Data cd2 = new CredDAO.Data(); + cd2.reconstitute(bb); + check(cd,cd2); + + // nulls + cd.expires = null; + cd.cred = null; + + bb = cd.bytify(); + cd2 = new CredDAO.Data(); + cd2.reconstitute(bb); + check(cd,cd2); + + } + + private void check(CredDAO.Data a, CredDAO.Data b) { + assertEquals(a.id,b.id); + assertEquals(a.ns,b.ns); + assertEquals(a.type,b.type); + if(a.cred==null) { + assertEquals(a.cred,b.cred); + } else { + int l = a.cred.limit(); + assertEquals(l,b.cred.limit()); + for (int i=0;i id = new CacheInfoDAO(trans, cluster, AUTHZ); + Date date = new Date(); + + id.touch(trans, RoleDAO.TABLE,1); + try { + Thread.sleep(3000); + } catch (InterruptedException e) { + } + Result rid = id.check(trans); + Assert.assertEquals(rid.status,Status.OK); + Date[] dates = CacheInfoDAO.info.get(RoleDAO.TABLE); + if(dates.length>0 && dates[1]!=null) { + System.out.println(Chrono.dateStamp(dates[1])); + System.out.println(Chrono.dateStamp(date)); + Assert.assertTrue(Math.abs(dates[1].getTime() - date.getTime())<20000); // allow for 4 seconds, given Remote DB + } + } + +} diff --git a/auth/auth-cass/src/test/java/org/onap/aaf/auth/dao/aaf/test/JU_CertDAO.java b/auth/auth-cass/src/test/java/org/onap/aaf/auth/dao/aaf/test/JU_CertDAO.java new file mode 100644 index 00000000..8e8ed6ea --- /dev/null +++ b/auth/auth-cass/src/test/java/org/onap/aaf/auth/dao/aaf/test/JU_CertDAO.java @@ -0,0 +1,103 @@ +/******************************************************************************* + * ============LICENSE_START==================================================== + * * org.onap.aaf + * * =========================================================================== + * * Copyright © 2017 AT&T Intellectual Property. All rights reserved. + * * =========================================================================== + * * 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==================================================== + * * + * * + ******************************************************************************/ +package org.onap.aaf.auth.dao.aaf.test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import java.io.IOException; +import java.math.BigInteger; +import java.nio.ByteBuffer; +import java.security.NoSuchAlgorithmException; +import java.util.List; + +import org.junit.Test; +import org.onap.aaf.auth.dao.cass.CertDAO; +import org.onap.aaf.auth.dao.cass.CertDAO.Data; +import org.onap.aaf.auth.layer.Result; +import org.onap.aaf.misc.env.APIException; + +/** + * UserDAO unit test. + * User: tp007s + * Date: 7/19/13 + */ +public class JU_CertDAO extends AbsJUCass { + @Test + public void test() throws IOException, NoSuchAlgorithmException, APIException { + CertDAO cdao = new CertDAO(trans,cluster,"authz"); + try { + // Create + CertDAO.Data data = new CertDAO.Data(); + data.serial=new BigInteger("11839383"); + data.id = "m55555@tguard.att.com"; + data.x500="CN=ju_cert.dao.att.com, OU=AAF, O=\"ATT Services, Inc.\", L=Southfield, ST=Michigan, C=US"; + data.x509="I'm a cert"; + data.ca = "aaf"; + cdao.create(trans,data); + +// Bytification + ByteBuffer bb = data.bytify(); + Data bdata = new CertDAO.Data(); + bdata.reconstitute(bb); + checkData1(data, bdata); + + // Validate Read with key fields in Data + Result> rlcd = cdao.read(trans,data); + assertTrue(rlcd.isOKhasData()); + for(CertDAO.Data d : rlcd.value) { + checkData1(data,d); + } + + // Validate Read with key fields in Data + rlcd = cdao.read(trans,data.ca,data.serial); + assertTrue(rlcd.isOKhasData()); + for(CertDAO.Data d : rlcd.value) { + checkData1(data,d); + } + + // Update + data.id = "m66666.tguard.att.com"; + cdao.update(trans,data); + rlcd = cdao.read(trans,data); + assertTrue(rlcd.isOKhasData()); + for(CertDAO.Data d : rlcd.value) { + checkData1(data,d); + } + + cdao.delete(trans,data, true); + } finally { + cdao.close(trans); + } + + + } + + private void checkData1(Data data, Data d) { + assertEquals(data.ca,d.ca); + assertEquals(data.serial,d.serial); + assertEquals(data.id,d.id); + assertEquals(data.x500,d.x500); + assertEquals(data.x509,d.x509); + } + +} diff --git a/auth/auth-cass/src/test/java/org/onap/aaf/auth/dao/aaf/test/JU_CredDAO.java b/auth/auth-cass/src/test/java/org/onap/aaf/auth/dao/aaf/test/JU_CredDAO.java new file mode 100644 index 00000000..bb88a2aa --- /dev/null +++ b/auth/auth-cass/src/test/java/org/onap/aaf/auth/dao/aaf/test/JU_CredDAO.java @@ -0,0 +1,250 @@ +/******************************************************************************* + * ============LICENSE_START==================================================== + * * org.onap.aaf + * * =========================================================================== + * * Copyright © 2017 AT&T Intellectual Property. All rights reserved. + * * =========================================================================== + * * 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==================================================== + * * + * * + ******************************************************************************/ +package org.onap.aaf.auth.dao.aaf.test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import java.io.IOException; +import java.nio.ByteBuffer; +import java.security.NoSuchAlgorithmException; +import java.util.Date; +import java.util.List; + +import org.junit.Test; +import org.onap.aaf.auth.dao.cass.CredDAO; +import org.onap.aaf.auth.dao.cass.CredDAO.Data; +import org.onap.aaf.auth.layer.Result; +import org.onap.aaf.misc.env.APIException; + +/** + * UserDAO unit test. + * User: tp007s + * Date: 7/19/13 + */ +public class JU_CredDAO extends AbsJUCass { + @Test + public void test() throws IOException, NoSuchAlgorithmException, APIException { + CredDAO udao = new CredDAO(trans,cluster,"authz"); + try { + // Create + CredDAO.Data data = new CredDAO.Data(); + data.id = "m55555@aaf.att.com"; + data.type = CredDAO.BASIC_AUTH; + data.notes = "temp pass"; + data.cred = ByteBuffer.wrap(userPassToBytes("m55555","mypass")); + data.other = 12; + data.expires = new Date(System.currentTimeMillis() + 60000*60*24*90); + udao.create(trans,data); + +// Bytification + ByteBuffer bb = data.bytify(); + Data bdata = new CredDAO.Data(); + bdata.reconstitute(bb); + checkData1(data, bdata); + + // Validate Read with key fields in Data + Result> rlcd = udao.read(trans,data); + assertTrue(rlcd.isOKhasData()); + for(CredDAO.Data d : rlcd.value) { + checkData1(data,d); + } + + // Update + data.cred = ByteBuffer.wrap(userPassToBytes("m55555","mynewpass")); + udao.update(trans,data); + rlcd = udao.read(trans,data); + assertTrue(rlcd.isOKhasData()); + for(CredDAO.Data d : rlcd.value) { + checkData1(data,d); + } + + udao.delete(trans,data, true); + } finally { + udao.close(trans); + } + + + } + + private void checkData1(Data data, Data d) { + assertEquals(data.id,d.id); + assertEquals(data.type,d.type); + assertEquals(data.ns,d.ns); + assertEquals(data.notes,d.notes); + assertEquals(data.cred,d.cred); + assertEquals(data.other,d.other); + assertEquals(data.expires,d.expires); + } + +// private String CONST_myName = "MyName"; +// public static final java.nio.ByteBuffer CONST_MY_CRED = get_CONST_MY_CRED(); +// public static final int CONST_CRED_TYPE = 11; +// +// public static final Date CONST_UPDATE_DATE = new Date(System.currentTimeMillis()+60000*24); +// @Test +// public void test() { +// UserDAO ud = new UserDAO(trans, cluster,"authz"); +// try { +// UserDAO.Data data = createPrototypeUserData(); +// ud.create(trans, data); +// +// // Validate Read with key fields in Data +// for(UserDAO.Data d : ud.read(trans, data)) { +// checkData1(data,d); +// } +// +// // Validate readByName +// for(UserDAO.Data d : ud.read(trans, CONST_myName)) { +// checkData1(data,d); +// } +// +// ud.delete(trans, data); +// List d_2 = ud.read(trans, CONST_myName); +// +// // Validate that data was deleted +// assertEquals("User should not be found after deleted", 0, d_2.size() ); +// +// data = new UserDAO.Data(); +// data.name = CONST_myName; +// data.cred = CONST_MY_CRED; +// data.cred_type= CONST_CRED_TYPE; +// data.expires = new Date(System.currentTimeMillis()+60000*24); +// final Result user = ud.r_create(trans, data); +// assertEquals("ud.createUser should work", Result.Status.OK, user.status); +// +// checkDataIgnoreDateDiff(data, user.value); +// +// // finally leave system in consistent state by deleting user again +// ud.delete(trans,data); +// +// } catch (DAOException e) { +// e.printStackTrace(); +// fail("Fail due to Exception"); +// } finally { +// ud.close(trans); +// } +// } +// +// private UserDAO.Data createPrototypeUserData() { +// UserDAO.Data data = new UserDAO.Data(); +// data.name = CONST_myName; +// +// data.cred_type = CONST_CRED_TYPE; +// data.cred = CONST_MY_CRED; +// data.expires = CONST_UPDATE_DATE; +// return data; +// } +// +// // @Test +// // public void testReadByUser() throws Exception { +// // // this test was done above in our super test, since it uses the same setup +// // } +// +// @Test +// public void testFunctionCreateUser() throws Exception { +// String name = "roger_rabbit"; +// Integer credType = CONST_CRED_TYPE; +// java.nio.ByteBuffer cred = CONST_MY_CRED; +// final UserDAO ud = new UserDAO(trans, cluster,"authz"); +// final UserDAO.Data data = createPrototypeUserData(); +// Result ret = ud.r_create(trans, data); +// Result> byUserNameLookup = ud.r_read(trans, name); +// +// assertEquals("sanity test w/ different username (different than other test cases) failed", name, byUserNameLookup.value.get(0).name); +// assertEquals("delete roger_rabbit failed", true, ud.delete(trans, byUserNameLookup.value.get(0))); +// } +// +// @Test +// public void testLowLevelCassandraCreateData_Given_UserAlreadyPresent_ShouldPass() throws Exception { +// UserDAO ud = new UserDAO(trans, cluster,"authz"); +// +// final UserDAO.Data data = createPrototypeUserData(); +// final UserDAO.Data data1 = ud.create(trans, data); +// final UserDAO.Data data2 = ud.create(trans, data); +// +// assertNotNull(data1); +// assertNotNull(data2); +// +// assertEquals(CONST_myName, data1.name); +// assertEquals(CONST_myName, data2.name); +// } +// +// @Test +// public void testCreateUser_Given_UserAlreadyPresent_ShouldFail() throws Exception { +// UserDAO ud = new UserDAO(trans, cluster,"authz"); +// +// final UserDAO.Data data = createPrototypeUserData(); +// +// // make sure that some prev test did not leave the user in the DB +// ud.delete(trans, data); +// +// // attempt to create same user twice !!! +// +// final Result data1 = ud.r_create(trans, data); +// final Result data2 = ud.r_create(trans, data); +// +// assertNotNull(data1); +// assertNotNull(data2); +// +// assertEquals(true, Result.Status.OK == data1.status); +// assertEquals(false, Result.Status.OK == data2.status); +// } +// +// private void checkData1(UserDAO.Data data, UserDAO.Data d) { +// data.name = CONST_myName; +// +// data.cred_type = CONST_CRED_TYPE; +// data.cred = CONST_MY_CRED; +// data.expires = CONST_UPDATE_DATE; +// +// assertEquals(data.name, d.name); +// assertEquals(data.cred_type, d.cred_type); +// assertEquals(data.cred, d.cred); +// assertEquals(data.expires, d.expires); +// +// } +// +// private void checkDataIgnoreDateDiff(UserDAO.Data data, UserDAO.Data d) { +// data.name = CONST_myName; +// +// data.cred_type = CONST_CRED_TYPE; +// data.cred = CONST_MY_CRED; +// data.expires = CONST_UPDATE_DATE; +// +// assertEquals(data.name, d.name); +// assertEquals(data.cred_type, d.cred_type); +// assertEquals(data.cred, d.cred); +// // we allow dates to be different, e.g. high level calls e.g. createUser sets the date itself. +// //assertEquals(data.updated, d.updated); +// +// } +// +// /** +// * Get a CONST_MY_CRED ByteBuffer, which is the java type for a cass blob. +// * @return +// */ +// private static java.nio.ByteBuffer get_CONST_MY_CRED() { +// return ByteBuffer.wrap("Hello".getBytes()); +// } +// +} diff --git a/auth/auth-cass/src/test/java/org/onap/aaf/auth/dao/aaf/test/JU_DelegateDAO.java b/auth/auth-cass/src/test/java/org/onap/aaf/auth/dao/aaf/test/JU_DelegateDAO.java new file mode 100644 index 00000000..a518e509 --- /dev/null +++ b/auth/auth-cass/src/test/java/org/onap/aaf/auth/dao/aaf/test/JU_DelegateDAO.java @@ -0,0 +1,106 @@ +/******************************************************************************* + * ============LICENSE_START==================================================== + * * org.onap.aaf + * * =========================================================================== + * * Copyright © 2017 AT&T Intellectual Property. All rights reserved. + * * =========================================================================== + * * 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==================================================== + * * + * * + ******************************************************************************/ +package org.onap.aaf.auth.dao.aaf.test; + + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import java.nio.ByteBuffer; +import java.util.Date; +import java.util.List; + +import org.junit.Test; +import org.onap.aaf.auth.dao.cass.DelegateDAO; +import org.onap.aaf.auth.dao.cass.DelegateDAO.Data; +import org.onap.aaf.auth.layer.Result; + + +public class JU_DelegateDAO extends AbsJUCass { + @Test + public void testCRUD() throws Exception { + DelegateDAO dao = new DelegateDAO(trans, cluster, AUTHZ); + DelegateDAO.Data data = new DelegateDAO.Data(); + data.user = "myname"; + data.delegate = "yourname"; + data.expires = new Date(); + +// Bytification + ByteBuffer bb = data.bytify(); + Data bdata = new DelegateDAO.Data(); + bdata.reconstitute(bb); + compare(data, bdata); + + try { + // Test create + Result ddcr = dao.create(trans,data); + assertTrue(ddcr.isOK()); + + + // Read by User + Result> records = dao.read(trans,data.user); + assertTrue(records.isOKhasData()); + for(DelegateDAO.Data rdata : records.value) + compare(data,rdata); + + // Read by Delegate + records = dao.readByDelegate(trans,data.delegate); + assertTrue(records.isOKhasData()); + for(DelegateDAO.Data rdata : records.value) + compare(data,rdata); + + // Update + data.delegate = "hisname"; + data.expires = new Date(); + assertTrue(dao.update(trans, data).isOK()); + + // Read by User + records = dao.read(trans,data.user); + assertTrue(records.isOKhasData()); + for(DelegateDAO.Data rdata : records.value) + compare(data,rdata); + + // Read by Delegate + records = dao.readByDelegate(trans,data.delegate); + assertTrue(records.isOKhasData()); + for(DelegateDAO.Data rdata : records.value) + compare(data,rdata); + + // Test delete + dao.delete(trans,data, true); + records = dao.read(trans,data.user); + assertTrue(records.isEmpty()); + + + } finally { + dao.close(trans); + } + } + + private void compare(Data d1, Data d2) { + assertEquals(d1.user, d2.user); + assertEquals(d1.delegate, d2.delegate); + assertEquals(d1.expires,d2.expires); + } + + +} diff --git a/auth/auth-cass/src/test/java/org/onap/aaf/auth/dao/aaf/test/JU_FastCalling.java b/auth/auth-cass/src/test/java/org/onap/aaf/auth/dao/aaf/test/JU_FastCalling.java new file mode 100644 index 00000000..d7886d3c --- /dev/null +++ b/auth/auth-cass/src/test/java/org/onap/aaf/auth/dao/aaf/test/JU_FastCalling.java @@ -0,0 +1,89 @@ +/******************************************************************************* + * ============LICENSE_START==================================================== + * * org.onap.aaf + * * =========================================================================== + * * Copyright © 2017 AT&T Intellectual Property. All rights reserved. + * * =========================================================================== + * * 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==================================================== + * * + * * + ******************************************************************************/ +package org.onap.aaf.auth.dao.aaf.test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import java.io.IOException; +import java.nio.ByteBuffer; +import java.security.NoSuchAlgorithmException; +import java.util.Date; +import java.util.List; + +import org.junit.Test; +import org.onap.aaf.auth.dao.cass.CredDAO; +import org.onap.aaf.auth.dao.cass.CredDAO.Data; +import org.onap.aaf.auth.layer.Result; +import org.onap.aaf.misc.env.APIException; + +public class JU_FastCalling extends AbsJUCass { + + @Test + public void test() throws IOException, NoSuchAlgorithmException, APIException { + trans.setProperty("cassandra.writeConsistency.cred","ONE"); + + CredDAO udao = new CredDAO(env.newTransNoAvg(),cluster,"authz"); + System.out.println("Starting calls"); + for(iterations=0;iterations<8;++iterations) { + try { + // Create + CredDAO.Data data = new CredDAO.Data(); + data.id = "m55555@aaf.att.com"; + data.type = CredDAO.BASIC_AUTH; + data.cred = ByteBuffer.wrap(userPassToBytes("m55555","mypass")); + data.expires = new Date(System.currentTimeMillis() + 60000*60*24*90); + udao.create(trans,data); + + // Validate Read with key fields in Data + Result> rlcd = udao.read(trans,data); + assertTrue(rlcd.isOKhasData()); + for(CredDAO.Data d : rlcd.value) { + checkData1(data,d); + } + + // Update + data.cred = ByteBuffer.wrap(userPassToBytes("m55555","mynewpass")); + udao.update(trans,data); + rlcd = udao.read(trans,data); + assertTrue(rlcd.isOKhasData()); + for(CredDAO.Data d : rlcd.value) { + checkData1(data,d); + } + + udao.delete(trans,data, true); + } finally { + updateTotals(); + newTrans(); + } + } + + } + + private void checkData1(Data data, Data d) { + assertEquals(data.id,d.id); + assertEquals(data.type,d.type); + assertEquals(data.cred,d.cred); + assertEquals(data.expires,d.expires); + } + +} diff --git a/auth/auth-cass/src/test/java/org/onap/aaf/auth/dao/aaf/test/JU_HistoryDAO.java b/auth/auth-cass/src/test/java/org/onap/aaf/auth/dao/aaf/test/JU_HistoryDAO.java new file mode 100644 index 00000000..0b552a49 --- /dev/null +++ b/auth/auth-cass/src/test/java/org/onap/aaf/auth/dao/aaf/test/JU_HistoryDAO.java @@ -0,0 +1,153 @@ +/******************************************************************************* + * ============LICENSE_START==================================================== + * * org.onap.aaf + * * =========================================================================== + * * Copyright © 2017 AT&T Intellectual Property. All rights reserved. + * * =========================================================================== + * * 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==================================================== + * * + * * + ******************************************************************************/ +package org.onap.aaf.auth.dao.aaf.test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +import java.nio.ByteBuffer; +import java.util.List; +import java.util.Random; + +import org.junit.Test; +import org.onap.aaf.auth.dao.cass.HistoryDAO; +import org.onap.aaf.auth.layer.Result; + +public class JU_HistoryDAO extends AbsJUCass { + + @Test + public void testCreate() throws Exception { + HistoryDAO historyDAO = new HistoryDAO(trans, cluster, AUTHZ); + HistoryDAO.Data data = createHistoryData(); + + try { + historyDAO.create(trans,data); + Thread.sleep(200);// History Create is Async + Result> records = historyDAO.readByUser(trans,data.user,data.yr_mon); + assertTrue(records.isOKhasData()); + for(HistoryDAO.Data d : records.value) { + assertHistory(data, d); + } + } finally { + historyDAO.close(trans); + } + } + + @Test + public void tesReadByUser() throws Exception { + HistoryDAO historyDAO = new HistoryDAO(trans,cluster, AUTHZ); + HistoryDAO.Data data = createHistoryData(); + + try { + historyDAO.create(trans,data); + Thread.sleep(200);// History Create is Async + Result> records = historyDAO.readByUser(trans, data.user,data.yr_mon); + assertTrue(records.isOKhasData()); + for(HistoryDAO.Data d : records.value) { + assertHistory(data, d); + } + } finally { + historyDAO.close(trans); + } + } + +/* + @Test + public void readByUserAndMonth() throws Exception { + HistoryDAO historyDAO = new HistoryDAO(trans,cluster, AUTHZ); + HistoryDAO.Data data = createHistoryData(); + + try { + historyDAO.create(trans,data); + Thread.sleep(200);// History Create is Async + Result> records = historyDAO.readByUserAndMonth(trans, + data.user, Integer.valueOf(String.valueOf(data.yr_mon).substring(0, 4)), + Integer.valueOf(String.valueOf(data.yr_mon).substring(4, 6))); + assertTrue(records.isOKhasData()); + for(HistoryDAO.Data d : records.value) { + assertHistory(data, d); + } + } finally { + historyDAO.close(trans); + } + } +*/ + //TODO readadd this +// @Test +// public void readByUserAndDay() throws Exception { +// HistoryDAO historyDAO = new HistoryDAO(trans, cluster, AUTHZ); +// HistoryDAO.Data data = createHistoryData(); +// +// try { +// historyDAO.create(trans, data); +// Thread.sleep(200);// History Create is Async +// +// String dayTime = String.valueOf(data.day_time); +// String day = null; +// if (dayTime.length() < 8) +// day = dayTime.substring(0, 1); +// else +// day = dayTime.substring(0, 2); +// +// List records = historyDAO.readByUserBetweenDates(trans, +// data.user, Integer.valueOf(String.valueOf(data.yr_mon).substring(0, 4)), +// Integer.valueOf(String.valueOf(data.yr_mon).substring(4, 6)), +// Integer.valueOf(day), 0); +// assertEquals(1,records.size()); +// for(HistoryDAO.Data d : records) { +// assertHistory(data, d); +// } +// } finally { +// historyDAO.close(trans); +// } +// } + private HistoryDAO.Data createHistoryData() { + HistoryDAO.Data data = HistoryDAO.newInitedData(); + Random random = new Random(); + data.user = "test" + random.nextInt(); + data.action = "add"; + data.target = "history"; + data.memo = "adding a row into history table"; +// data.detail().put("id", "test"); +// data.detail().put("name", "test"); + //String temp = "Test Blob Message"; + data.reconstruct = ByteBuffer.wrap("Temp Blob Message".getBytes()); + return data; + } + + private void assertHistory(HistoryDAO.Data ip, HistoryDAO.Data op) { + assertEquals(ip.yr_mon, op.yr_mon); +// assertEquals(ip.day_time, op.day_time); + assertEquals(ip.user, op.user); + assertEquals(ip.action, op.action); + assertEquals(ip.target, op.target); + assertEquals(ip.memo, op.memo); + //TODO : have to see if third party assert utility can be used +// assertTrue(CollectionUtils.isEqualCollection(ip.detail, op.detail)); +// for (String key : ip.detail().keySet()) { +// assertNotNull(op.detail().get(key)); +// } + assertNotNull(op.reconstruct); + } + +} diff --git a/auth/auth-cass/src/test/java/org/onap/aaf/auth/dao/aaf/test/JU_NsDAO.java b/auth/auth-cass/src/test/java/org/onap/aaf/auth/dao/aaf/test/JU_NsDAO.java new file mode 100644 index 00000000..eb064959 --- /dev/null +++ b/auth/auth-cass/src/test/java/org/onap/aaf/auth/dao/aaf/test/JU_NsDAO.java @@ -0,0 +1,185 @@ +/******************************************************************************* + * ============LICENSE_START==================================================== + * * org.onap.aaf + * * =========================================================================== + * * Copyright © 2017 AT&T Intellectual Property. All rights reserved. + * * =========================================================================== + * * 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==================================================== + * * + * * + ******************************************************************************/ +package org.onap.aaf.auth.dao.aaf.test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import java.io.IOException; +import java.nio.ByteBuffer; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; + +import org.junit.Test; +import org.onap.aaf.auth.dao.cass.NsDAO; +import org.onap.aaf.auth.dao.cass.NsType; +import org.onap.aaf.auth.dao.cass.NsDAO.Data; +import org.onap.aaf.auth.layer.Result; +import org.onap.aaf.misc.env.APIException; + + +public class JU_NsDAO extends AbsJUCass { + private static final String CRM = "ju_crm"; + private static final String SWM = "ju_swm"; + + @Test + public void test() throws APIException, IOException { + NsDAO nsd = new NsDAO(trans, cluster, AUTHZ); + try { + final String nsparent = "com.test"; + final String ns1 = nsparent +".ju_ns"; + final String ns2 = nsparent + ".ju_ns2"; + + Map oAttribs = new HashMap(); + oAttribs.put(SWM, "swm_data"); + oAttribs.put(CRM, "crm_data"); + Data data = new NsDAO.Data(); + data.name = ns1; + data.type = NsType.APP.type; + data.attrib(true).putAll(oAttribs); + + + Result> rdrr; + + // CREATE + Result rdc = nsd.create(trans, data); + assertTrue(rdc.isOK()); + + try { +// Bytification + ByteBuffer bb = data.bytify(); + Data bdata = new NsDAO.Data(); + bdata.reconstitute(bb); + compare(data, bdata); + + // Test READ by Object + rdrr = nsd.read(trans, data); + assertTrue(rdrr.isOKhasData()); + assertEquals(rdrr.value.size(),1); + Data d = rdrr.value.get(0); + assertEquals(d.name,data.name); + assertEquals(d.type,data.type); + attribsEqual(d.attrib(false),data.attrib(false)); + attribsEqual(oAttribs,data.attrib(false)); + + // Test Read by Key + rdrr = nsd.read(trans, data.name); + assertTrue(rdrr.isOKhasData()); + assertEquals(rdrr.value.size(),1); + d = rdrr.value.get(0); + assertEquals(d.name,data.name); + assertEquals(d.type,data.type); + attribsEqual(d.attrib(false),data.attrib(false)); + attribsEqual(oAttribs,data.attrib(false)); + + // Read NS by Type + Result> rtypes = nsd.readNsByAttrib(trans, SWM); + Set types; + if(rtypes.notOK()) { + throw new IOException(rtypes.errorString()); + } else { + types = rtypes.value; + } + assertEquals(1,types.size()); + assertEquals(true,types.contains(ns1)); + + // Add second NS to test list of data returned + Data data2 = new NsDAO.Data(); + data2.name = ns2; + data2.type = 3; // app + Result rdc2 = nsd.create(trans, data2); + assertTrue(rdc2.isOK()); + + // Interrupt - test PARENT + Result> rdchildren = nsd.getChildren(trans, "com.test"); + assertTrue(rdchildren.isOKhasData()); + boolean child1 = false; + boolean child2 = false; + for(Data dchild : rdchildren.value) { + if(ns1.equals(dchild.name))child1=true; + if(ns2.equals(dchild.name))child2=true; + } + assertTrue(child1); + assertTrue(child2); + + // FINISH DATA 2 by deleting + Result rddr = nsd.delete(trans, data2, true); + assertTrue(rddr.isOK()); + + // ADD DESCRIPTION + String description = "This is my test Namespace"; + assertFalse(description.equalsIgnoreCase(data.description)); + + Result addDesc = nsd.addDescription(trans, data.name, description); + assertTrue(addDesc.isOK()); + rdrr = nsd.read(trans, data); + assertTrue(rdrr.isOKhasData()); + assertEquals(rdrr.value.size(),1); + assertEquals(rdrr.value.get(0).description,description); + + // UPDATE + String newDescription = "zz1234 Owns This Namespace Now"; + oAttribs.put("mso", "mso_data"); + data.attrib(true).put("mso", "mso_data"); + data.description = newDescription; + Result update = nsd.update(trans, data); + assertTrue(update.isOK()); + rdrr = nsd.read(trans, data); + assertTrue(rdrr.isOKhasData()); + assertEquals(rdrr.value.size(),1); + assertEquals(rdrr.value.get(0).description,newDescription); + attribsEqual(oAttribs, rdrr.value.get(0).attrib); + + + } catch (IOException e) { + e.printStackTrace(); + } finally { + // DELETE + Result rddr = nsd.delete(trans, data, true); + assertTrue(rddr.isOK()); + rdrr = nsd.read(trans, data); + assertTrue(rdrr.isOK() && rdrr.isEmpty()); + assertEquals(rdrr.value.size(),0); + } + } finally { + nsd.close(trans); + } + } + + private void compare(NsDAO.Data d, NsDAO.Data data) { + assertEquals(d.name,data.name); + assertEquals(d.type,data.type); + attribsEqual(d.attrib(false),data.attrib(false)); + attribsEqual(d.attrib(false),data.attrib(false)); + } + + private void attribsEqual(Map aa, Map ba) { + assertEquals(aa.size(),ba.size()); + for(Entry es : aa.entrySet()) { + assertEquals(es.getValue(),ba.get(es.getKey())); + } + } +} diff --git a/auth/auth-cass/src/test/java/org/onap/aaf/auth/dao/aaf/test/JU_NsType.java b/auth/auth-cass/src/test/java/org/onap/aaf/auth/dao/aaf/test/JU_NsType.java new file mode 100644 index 00000000..06e5f0ed --- /dev/null +++ b/auth/auth-cass/src/test/java/org/onap/aaf/auth/dao/aaf/test/JU_NsType.java @@ -0,0 +1,58 @@ +/******************************************************************************* + * ============LICENSE_START==================================================== + * * org.onap.aaf + * * =========================================================================== + * * Copyright © 2017 AT&T Intellectual Property. All rights reserved. + * * =========================================================================== + * * 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==================================================== + * * + * * + ******************************************************************************/ +package org.onap.aaf.auth.dao.aaf.test; + +import static org.junit.Assert.assertEquals; + +import org.junit.AfterClass; +import org.junit.Test; +import org.onap.aaf.auth.dao.cass.NsType; + +public class JU_NsType { + + @AfterClass + public static void tearDownAfterClass() throws Exception { + } + + @Test + public void test() { + NsType nt,nt2; + String[] tests = new String[] {"DOT","ROOT","COMPANY","APP","STACKED_APP","STACK"}; + for(String s : tests) { + nt = NsType.valueOf(s); + assertEquals(s,nt.name()); + + nt2 = NsType.fromString(s); + assertEquals(nt,nt2); + + int t = nt.type; + nt2 = NsType.fromType(t); + assertEquals(nt,nt2); + } + + nt = NsType.fromType(Integer.MIN_VALUE); + assertEquals(nt,NsType.UNKNOWN); + nt = NsType.fromString("Garbage"); + assertEquals(nt,NsType.UNKNOWN); + } + +} diff --git a/auth/auth-cass/src/test/java/org/onap/aaf/auth/dao/aaf/test/JU_PermDAO.java b/auth/auth-cass/src/test/java/org/onap/aaf/auth/dao/aaf/test/JU_PermDAO.java new file mode 100644 index 00000000..1a407af7 --- /dev/null +++ b/auth/auth-cass/src/test/java/org/onap/aaf/auth/dao/aaf/test/JU_PermDAO.java @@ -0,0 +1,174 @@ +/******************************************************************************* + * ============LICENSE_START==================================================== + * * org.onap.aaf + * * =========================================================================== + * * Copyright © 2017 AT&T Intellectual Property. All rights reserved. + * * =========================================================================== + * * 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==================================================== + * * + * * + ******************************************************************************/ +package org.onap.aaf.auth.dao.aaf.test; + +import static junit.framework.Assert.assertEquals; +import static junit.framework.Assert.assertTrue; + +import java.io.IOException; +import java.nio.ByteBuffer; +import java.util.List; +import java.util.Set; + +import org.junit.Test; +import org.onap.aaf.auth.dao.cass.PermDAO; +import org.onap.aaf.auth.dao.cass.RoleDAO; +import org.onap.aaf.auth.dao.cass.PermDAO.Data; +import org.onap.aaf.auth.layer.Result; +import org.onap.aaf.misc.env.APIException; + +/** + * Test the PermissionDAO + * + * Utilize AbsJUCass to initialize and pre-load Cass + * + * + */ +public class JU_PermDAO extends AbsJUCass{ + + @Test + public void test() throws APIException, IOException { + PermDAO pd = new PermDAO(trans,cluster,"authz"); + try { + PermDAO.Data data = new PermDAO.Data(); + data.ns = "com.test.ju_perm"; + data.type = "MyType"; + data.instance = "MyInstance"; + data.action = "MyAction"; + data.roles(true).add(data.ns + ".dev"); + + + + // CREATE + Result rpdc = pd.create(trans,data); + assertTrue(rpdc.isOK()); + + Result> rlpd; + try { +// Bytification + ByteBuffer bb = data.bytify(); + Data bdata = new PermDAO.Data(); + bdata.reconstitute(bb); + compare(data, bdata); + + // Validate Read with key fields in Data + if((rlpd = pd.read(trans,data)).isOK()) + for(PermDAO.Data d : rlpd.value) { + checkData1(data,d); + } + + // Validate readByName + if((rlpd = pd.readByType(trans,data.ns, data.type)).isOK()) + for(PermDAO.Data d : rlpd.value) { + checkData1(data,d); + } + + // Add Role + RoleDAO.Data role = new RoleDAO.Data(); + role.ns = data.ns; + role.name = "test"; + + Result rvpd = pd.addRole(trans, data, role.fullName()); + assertTrue(rvpd.isOK()); + // Validate Read with key fields in Data + if((rlpd = pd.read(trans,data)).isOK()) + for(PermDAO.Data d : rlpd.value) { + checkData2(data,d); + } + + // Remove Role + rvpd = pd.delRole(trans, data, role.fullName()); + assertTrue(rvpd.isOK()); + if((rlpd = pd.read(trans,data)).isOK()) + for(PermDAO.Data d : rlpd.value) { + checkData1(data,d); + } + + // Add Child + Data data2 = new Data(); + data2.ns = data.ns; + data2.type = data.type + ".2"; + data2.instance = data.instance; + data2.action = data.action; + + rpdc = pd.create(trans, data2); + assertTrue(rpdc.isOK()); + try { + rlpd = pd.readChildren(trans, data.ns,data.type); + assertTrue(rlpd.isOKhasData()); + assertEquals(rlpd.value.size(),1); + assertEquals(rlpd.value.get(0).fullType(),data2.fullType()); + } finally { + // Delete Child + pd.delete(trans, data2,true); + + } + } catch (IOException e) { + e.printStackTrace(); + } finally { + // DELETE + Result rpdd = pd.delete(trans,data,true); + assertTrue(rpdd.isOK()); + rlpd = pd.read(trans, data); + assertTrue(rlpd.isOK() && rlpd.isEmpty()); + assertEquals(rlpd.value.size(),0); + } + } finally { + pd.close(trans); + } + } + + private void compare(Data a, Data b) { + assertEquals(a.ns,b.ns); + assertEquals(a.type,b.type); + assertEquals(a.instance,b.instance); + assertEquals(a.action,b.action); + assertEquals(a.roles(false).size(),b.roles(false).size()); + for(String s: a.roles(false)) { + assertTrue(b.roles(false).contains(s)); + } + } + private void checkData1(Data data, Data d) { + assertEquals(data.ns,d.ns); + assertEquals(data.type,d.type); + assertEquals(data.instance,d.instance); + assertEquals(data.action,d.action); + + Set ss = d.roles(true); + assertEquals(1,ss.size()); + assertTrue(ss.contains(data.ns+".dev")); + } + + private void checkData2(Data data, Data d) { + assertEquals(data.ns,d.ns); + assertEquals(data.type,d.type); + assertEquals(data.instance,d.instance); + assertEquals(data.action,d.action); + + Set ss = d.roles(true); + assertEquals(2,ss.size()); + assertTrue(ss.contains(data.ns+".dev")); + assertTrue(ss.contains(data.ns+".test")); + } + + +} diff --git a/auth/auth-cass/src/test/java/org/onap/aaf/auth/dao/aaf/test/JU_RoleDAO.java b/auth/auth-cass/src/test/java/org/onap/aaf/auth/dao/aaf/test/JU_RoleDAO.java new file mode 100644 index 00000000..fda818fc --- /dev/null +++ b/auth/auth-cass/src/test/java/org/onap/aaf/auth/dao/aaf/test/JU_RoleDAO.java @@ -0,0 +1,137 @@ +/******************************************************************************* + * ============LICENSE_START==================================================== + * * org.onap.aaf + * * =========================================================================== + * * Copyright © 2017 AT&T Intellectual Property. All rights reserved. + * * =========================================================================== + * * 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==================================================== + * * + * * + ******************************************************************************/ +package org.onap.aaf.auth.dao.aaf.test; + +import static junit.framework.Assert.assertEquals; +import static junit.framework.Assert.assertTrue; + +import java.io.IOException; +import java.nio.ByteBuffer; +import java.util.List; + +import org.junit.Test; +import org.onap.aaf.auth.dao.cass.PermDAO; +import org.onap.aaf.auth.dao.cass.RoleDAO; +import org.onap.aaf.auth.dao.cass.RoleDAO.Data; +import org.onap.aaf.auth.layer.Result; +import org.onap.aaf.misc.env.APIException; + + +public class JU_RoleDAO extends AbsJUCass { + + @Test + public void test() throws IOException, APIException { + RoleDAO rd = new RoleDAO(trans, cluster, AUTHZ); + try { + Data data = new RoleDAO.Data(); + data.ns = "com.test.ju_role"; + data.name = "role1"; + +// Bytification + ByteBuffer bb = data.bytify(); + Data bdata = new RoleDAO.Data(); + bdata.reconstitute(bb); + compare(data, bdata); + + // CREATE + Result rdc = rd.create(trans, data); + assertTrue(rdc.isOK()); + Result> rdrr; + try { + // READ + rdrr = rd.read(trans, data); + assertTrue(rdrr.isOKhasData()); + assertEquals(rdrr.value.size(),1); + Data d = rdrr.value.get(0); + assertEquals(d.perms.size(),0); + assertEquals(d.name,data.name); + assertEquals(d.ns,data.ns); + + PermDAO.Data perm = new PermDAO.Data(); + perm.ns = data.ns; + perm.type = "Perm"; + perm.instance = "perm1"; + perm.action = "write"; + + // ADD Perm + Result rdar = rd.addPerm(trans, data, perm); + assertTrue(rdar.isOK()); + rdrr = rd.read(trans, data); + assertTrue(rdrr.isOKhasData()); + assertEquals(rdrr.value.size(),1); + assertEquals(rdrr.value.get(0).perms.size(),1); + assertTrue(rdrr.value.get(0).perms.contains(perm.encode())); + + // DEL Perm + rdar = rd.delPerm(trans, data,perm); + assertTrue(rdar.isOK()); + rdrr = rd.read(trans, data); + assertTrue(rdrr.isOKhasData()); + assertEquals(rdrr.value.size(),1); + assertEquals(rdrr.value.get(0).perms.size(),0); + + // Add Child + Data data2 = new Data(); + data2.ns = data.ns; + data2.name = data.name + ".2"; + + rdc = rd.create(trans, data2); + assertTrue(rdc.isOK()); + try { + rdrr = rd.readChildren(trans, data.ns,data.name); + assertTrue(rdrr.isOKhasData()); + assertEquals(rdrr.value.size(),1); + assertEquals(rdrr.value.get(0).name,data.name + ".2"); + + rdrr = rd.readChildren(trans, data.ns,"*"); + assertTrue(rdrr.isOKhasData()); + assertEquals(rdrr.value.size(),2); + + } finally { + // Delete Child + rd.delete(trans, data2, true); + } + + } finally { + // DELETE + Result rddr = rd.delete(trans, data, true); + assertTrue(rddr.isOK()); + rdrr = rd.read(trans, data); + assertTrue(rdrr.isOK() && rdrr.isEmpty()); + assertEquals(rdrr.value.size(),0); + } + } finally { + rd.close(trans); + } + } + + private void compare(Data a, Data b) { + assertEquals(a.name,b.name); + assertEquals(a.description, b.description); + assertEquals(a.ns,b.ns); + assertEquals(a.perms(false).size(),b.perms(false).size()); + for(String p : a.perms(false)) { + assertTrue(b.perms(false).contains(p)); + } + } + +} diff --git a/auth/auth-cass/src/test/java/org/onap/aaf/auth/direct/test/JU_DirectAAFLur.java b/auth/auth-cass/src/test/java/org/onap/aaf/auth/direct/test/JU_DirectAAFLur.java new file mode 100644 index 00000000..79d30c4c --- /dev/null +++ b/auth/auth-cass/src/test/java/org/onap/aaf/auth/direct/test/JU_DirectAAFLur.java @@ -0,0 +1,63 @@ +/******************************************************************************* + * ============LICENSE_START==================================================== + * * org.onap.aaf + * * =========================================================================== + * * Copyright © 2017 AT&T Intellectual Property. All rights reserved. + * * =========================================================================== + * * 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==================================================== + * * + * * + ******************************************************************************/ +package org.onap.aaf.auth.direct.test; + +import static org.junit.Assert.assertTrue; + +import java.security.Principal; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.onap.aaf.auth.dao.hl.Question; +import org.onap.aaf.auth.direct.DirectAAFLur; +import org.onap.aaf.auth.env.AuthzEnv; +import org.onap.aaf.cadi.Permission; +import org.powermock.modules.junit4.PowerMockRunner; +@RunWith(PowerMockRunner.class) +public class JU_DirectAAFLur { + +public static AuthzEnv env; +public static Question question; +public DirectAAFLur directAAFLur; + + + + @Before + public void setUp() + { + directAAFLur = new DirectAAFLur(env, question); + } + + @Test + public void testFish() + { + + Principal bait = null; + Permission pond=null; + directAAFLur.fish(bait, pond); + + assertTrue(true); + + } + +} diff --git a/auth/auth-cass/src/test/java/org/onap/aaf/auth/direct/test/JU_DirectAAFUserPass.java b/auth/auth-cass/src/test/java/org/onap/aaf/auth/direct/test/JU_DirectAAFUserPass.java new file mode 100644 index 00000000..6a25d991 --- /dev/null +++ b/auth/auth-cass/src/test/java/org/onap/aaf/auth/direct/test/JU_DirectAAFUserPass.java @@ -0,0 +1,84 @@ +/******************************************************************************* + * ============LICENSE_START==================================================== + * * org.onap.aaf + * * =========================================================================== + * * Copyright © 2017 AT&T Intellectual Property. All rights reserved. + * * =========================================================================== + * * 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==================================================== + * * + * * + ******************************************************************************/ +package org.onap.aaf.auth.direct.test; + +import static org.junit.Assert.*; + +import org.junit.Before; +import org.junit.Test; + +import static org.mockito.Mockito.*; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.runners.MockitoJUnitRunner; +import org.onap.aaf.auth.dao.hl.Question; +import org.onap.aaf.auth.direct.DirectAAFUserPass; +import org.onap.aaf.auth.env.AuthzEnv; +import org.onap.aaf.cadi.CredVal.Type; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.core.classloader.annotations.SuppressStaticInitializationFor; +import org.powermock.modules.junit4.PowerMockRunner; + +@RunWith(PowerMockRunner.class) +public class JU_DirectAAFUserPass { + + // TODO: Ian - This test is in shambles. fix it + + //public static AuthzEnv env; + //public static Question question; + public DirectAAFUserPass directAAFUserPass; + + @Mock + AuthzEnv env; + + @Mock + Question question; + + String user; + + Type type; + + byte[] pass; + + @Before + public void setUp() { + directAAFUserPass = new DirectAAFUserPass(env, question); + } + + @Test + public void testvalidate(){ + + // Boolean bolVal = directAAFUserPass.validate(user, type, pass); + // assertEquals((bolVal==null),true); + + assertTrue(true); + + } + + @Test + public void notYetTested() { + fail("Tests not yet implemented"); + } + +} diff --git a/auth/auth-cass/src/test/java/org/onap/aaf/auth/direct/test/JU_DirectCertIdentity.java b/auth/auth-cass/src/test/java/org/onap/aaf/auth/direct/test/JU_DirectCertIdentity.java new file mode 100644 index 00000000..07cd7ae9 --- /dev/null +++ b/auth/auth-cass/src/test/java/org/onap/aaf/auth/direct/test/JU_DirectCertIdentity.java @@ -0,0 +1,71 @@ +/******************************************************************************* + * ============LICENSE_START==================================================== + * * org.onap.aaf + * * =========================================================================== + * * Copyright © 2017 AT&T Intellectual Property. All rights reserved. + * * =========================================================================== + * * 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==================================================== + * * + * * + ******************************************************************************/ +package org.onap.aaf.auth.direct.test; + +import static org.junit.Assert.*; + +import java.security.Principal; +import java.security.cert.CertificateException; +import java.security.cert.X509Certificate; + +import javax.servlet.http.HttpServletRequest; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.onap.aaf.auth.dao.cached.CachedCertDAO; +import org.onap.aaf.auth.direct.DirectCertIdentity; +import org.powermock.modules.junit4.PowerMockRunner; + +@RunWith(PowerMockRunner.class) +public class JU_DirectCertIdentity { + + public DirectCertIdentity directCertIdentity; + + @Before + public void setUp(){ + directCertIdentity = new DirectCertIdentity(); + } + + + @Mock + HttpServletRequest req; + X509Certificate cert; + byte[] _certBytes; + + @Test + public void testidentity(){ + + try { + Principal p = directCertIdentity.identity(req, cert, _certBytes); + assertEquals(( (p) == null),true); + + } catch (CertificateException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + //assertTrue(true); + + } + +} diff --git a/auth/auth-certman/.gitignore b/auth/auth-certman/.gitignore new file mode 100644 index 00000000..70922378 --- /dev/null +++ b/auth/auth-certman/.gitignore @@ -0,0 +1,6 @@ +/target/ +/logs/ +/.settings/ +/.classpath +/tokens/ +/.project diff --git a/auth/auth-certman/pom.xml b/auth/auth-certman/pom.xml new file mode 100644 index 00000000..42be0418 --- /dev/null +++ b/auth/auth-certman/pom.xml @@ -0,0 +1,117 @@ + + + + 4.0.0 + + org.onap.aaf.auth + parent + 2.1.0-SNAPSHOT + ../pom.xml + + + aaf-auth-certman + AAF Auth Certificate Manager + Certificate Manager API + + + 21 + + + + + org.onap.aaf.auth + aaf-auth-core + + + + org.onap.aaf.auth + aaf-auth-cass + + + + org.onap.aaf.cadi + aaf-cadi-aaf + + + + com.google.code.jscep + jscep + 2.4.0 + + + + + + + + org.apache.maven.plugins + maven-jar-plugin + + + **/*.class + + + 2.3.1 + + + + + org.apache.maven.plugins + maven-deploy-plugin + + true + + + + org.codehaus.mojo + appassembler-maven-plugin + + + + org.onap.aaf.auth.cm.AAF_CM + cm + + cadi_prop_files=${project.conf_dir}/org.osaaf.cm.props + + + + + + + + + + + + nexus + attarch-releases + http://mavencentral.it.att.com:8084/nexus/content/repositories/attarch-releases + + + nexus + attarch-snapshots + http://mavencentral.it.att.com:8084/nexus/content/repositories/attarch-snapshots + + + diff --git a/auth/auth-certman/src/main/config/.gitignore b/auth/auth-certman/src/main/config/.gitignore new file mode 100644 index 00000000..e53ef90a --- /dev/null +++ b/auth/auth-certman/src/main/config/.gitignore @@ -0,0 +1 @@ +/log4j.properties diff --git a/auth/auth-certman/src/main/config/certman.props b/auth/auth-certman/src/main/config/certman.props new file mode 100644 index 00000000..1cd42f48 --- /dev/null +++ b/auth/auth-certman/src/main/config/certman.props @@ -0,0 +1,22 @@ +## +## AUTHZ Certman (authz-certman) Properties +## + +hostname=_HOSTNAME_ + +## DISCOVERY (DME2) Parameters on the Command Line +AFT_LATITUDE=_AFT_LATITUDE_ +AFT_LONGITUDE=_AFT_LONGITUDE_ +AFT_ENVIRONMENT=_AFT_ENVIRONMENT_ +DEPLOYED_VERSION=_ARTIFACT_VERSION_ + +## Pull in common/security properties + +cadi_prop_files=_COMMON_DIR_/com.att.aaf.common.props:_COMMON_DIR_/com.att.aaf.props + +##DME2 related parameters +DMEServiceName=service=com.att.authz.certman/version=_MAJOR_VER_._MINOR_VER_._PATCH_VER_/envContext=_ENV_CONTEXT_/routeOffer=_ROUTE_OFFER_ +AFT_DME2_PORT_RANGE=_AUTHZ_CERTMAN_PORT_RANGE_ + + + diff --git a/auth/auth-certman/src/main/java/org/onap/aaf/auth/cm/AAF_CM.java b/auth/auth-certman/src/main/java/org/onap/aaf/auth/cm/AAF_CM.java new file mode 100644 index 00000000..c1bc8202 --- /dev/null +++ b/auth/auth-certman/src/main/java/org/onap/aaf/auth/cm/AAF_CM.java @@ -0,0 +1,239 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + + +package org.onap.aaf.auth.cm; + +import java.lang.reflect.Constructor; +import java.util.Map; +import java.util.Map.Entry; +import java.util.TreeMap; + +import javax.servlet.Filter; + +import org.onap.aaf.auth.cache.Cache; +import org.onap.aaf.auth.cache.Cache.Dated; +import org.onap.aaf.auth.cm.api.API_Artifact; +import org.onap.aaf.auth.cm.api.API_Cert; +import org.onap.aaf.auth.cm.ca.CA; +import org.onap.aaf.auth.cm.facade.Facade1_0; +import org.onap.aaf.auth.cm.facade.FacadeFactory; +import org.onap.aaf.auth.cm.mapper.Mapper.API; +import org.onap.aaf.auth.cm.service.CMService; +import org.onap.aaf.auth.cm.service.Code; +import org.onap.aaf.auth.dao.CassAccess; +import org.onap.aaf.auth.dao.cass.LocateDAO; +import org.onap.aaf.auth.direct.DirectLocatorCreator; +import org.onap.aaf.auth.direct.DirectRegistrar; +import org.onap.aaf.auth.env.AuthzEnv; +import org.onap.aaf.auth.env.AuthzTrans; +import org.onap.aaf.auth.env.AuthzTransFilter; +import org.onap.aaf.auth.rserv.HttpMethods; +import org.onap.aaf.auth.server.AbsService; +import org.onap.aaf.auth.server.JettyServiceStarter; +import org.onap.aaf.cadi.Access; +import org.onap.aaf.cadi.CadiException; +import org.onap.aaf.cadi.LocatorException; +import org.onap.aaf.cadi.PropAccess; +import org.onap.aaf.cadi.Access.Level; +import org.onap.aaf.cadi.aaf.v2_0.AAFAuthn; +import org.onap.aaf.cadi.aaf.v2_0.AAFLurPerm; +import org.onap.aaf.cadi.aaf.v2_0.AAFTrustChecker; +import org.onap.aaf.cadi.aaf.v2_0.AbsAAFLocator; +import org.onap.aaf.cadi.config.Config; +import org.onap.aaf.cadi.register.Registrant; +import org.onap.aaf.misc.env.APIException; +import org.onap.aaf.misc.env.Data; +import org.onap.aaf.misc.env.Env; +import org.onap.aaf.misc.env.util.Split; + +import com.datastax.driver.core.Cluster; + +public class AAF_CM extends AbsService { + + private static final String USER_PERMS = "userPerms"; + private static final Map certAuths = new TreeMap(); + public Facade1_0 facade1_0; // this is the default Facade + public Facade1_0 facade1_0_XML; // this is the XML Facade + public Map cacheUser; + public AAFAuthn aafAuthn; + public AAFLurPerm aafLurPerm; + final public Cluster cluster; + public final LocateDAO locateDAO; + + + /** + * Construct AuthzAPI with all the Context Supporting Routes that Authz needs + * + * @param env + * @param si + * @param dm + * @param decryptor + * @throws APIException + */ + public AAF_CM(AuthzEnv env) throws Exception { + super(env.access(),env); + aafLurPerm = aafCon().newLur(); + // Note: If you need both Authn and Authz construct the following: + aafAuthn = aafCon().newAuthn(aafLurPerm); + + String aaf_env = env.getProperty(Config.AAF_ENV); + if(aaf_env==null) { + throw new APIException("aaf_env needs to be set"); + } + + // Initialize Facade for all uses + AuthzTrans trans = env.newTrans(); + + cluster = org.onap.aaf.auth.dao.CassAccess.cluster(env,null); + locateDAO = new LocateDAO(trans,cluster,CassAccess.KEYSPACE); + + // Have AAFLocator object Create DirectLocators for Location needs + AbsAAFLocator.setCreator(new DirectLocatorCreator(env, locateDAO)); + + // Load Supported Certificate Authorities by property + // Note: Some will be dynamic Properties, so we need to look through all + for(Entry es : env.access().getProperties().entrySet()) { + String key = es.getKey().toString(); + if(key.startsWith(CA.CM_CA_PREFIX)) { + int idx = key.indexOf('.'); + if(idx==key.lastIndexOf('.')) { // else it's a regular property + + env.log(Level.INIT, "Loading Certificate Authority Module: " + key.substring(idx+1)); + String[] segs = Split.split(',', env.getProperty(key)); + if(segs.length>0) { + String[][] multiParams = new String[segs.length-1][]; + for(int i=0;i cac = (Class)Class.forName(segs[0]); + Constructor cons = cac.getConstructor(new Class[] { + Access.class,String.class,String.class,String[][].class + }); + Object pinst[] = new Object[4]; + pinst[0]=env; + pinst[1]= key.substring(idx+1); + pinst[2]= aaf_env; + pinst[3] = multiParams; + CA ca = cons.newInstance(pinst); + certAuths.put(ca.getName(),ca); + } + } + } + } + if(certAuths.size()==0) { + throw new APIException("No Certificate Authorities have been configured in CertMan"); + } + + CMService service = new CMService(trans, this); + // note: Service knows how to shutdown Cluster on Shutdown, etc. See Constructor + facade1_0 = FacadeFactory.v1_0(this,trans, service,Data.TYPE.JSON); // Default Facade + facade1_0_XML = FacadeFactory.v1_0(this,trans,service,Data.TYPE.XML); + + + synchronized(env) { + if(cacheUser == null) { + cacheUser = Cache.obtain(USER_PERMS); + Cache.startCleansing(env, USER_PERMS); + } + } + + //////////////////////////////////////////////////////////////////////////// + // APIs + //////////////////////////////////////////////////////////////////////// + API_Cert.init(this); + API_Artifact.init(this); + + StringBuilder sb = new StringBuilder(); + trans.auditTrail(2, sb); + trans.init().log(sb); + } + + public CA getCA(String key) { + return certAuths.get(key); + } + + /** + * Setup XML and JSON implementations for each supported Version type + * + * We do this by taking the Code passed in and creating clones of these with the appropriate Facades and properties + * to do Versions and Content switches + * + */ + public void route(HttpMethods meth, String path, API api, Code code) throws Exception { + String version = "1.0"; + // Get Correct API Class from Mapper + Class respCls = facade1_0.mapper().getClass(api); + if(respCls==null) throw new Exception("Unknown class associated with " + api.getClass().getName() + ' ' + api.name()); + // setup Application API HTML ContentTypes for JSON and Route + String application = applicationJSON(respCls, version); + route(env,meth,path,code,application,"application/json;version="+version,"*/*"); + + // setup Application API HTML ContentTypes for XML and Route + application = applicationXML(respCls, version); + route(env,meth,path,code.clone(facade1_0_XML),application,"application/xml;version="+version); + + // Add other Supported APIs here as created + } + + public void routeAll(HttpMethods meth, String path, API api, Code code) throws Exception { + route(env,meth,path,code,""); // this will always match + } + + @Override + public Filter[] filters() throws CadiException, LocatorException { + try { + return new Filter[] { + new AuthzTransFilter(env,aafCon(), + new AAFTrustChecker((Env)env)) + }; + } catch (NumberFormatException e) { + throw new CadiException("Invalid Property information", e); + } + } + + @SuppressWarnings("unchecked") + @Override + public Registrant[] registrants(final int port) throws CadiException, LocatorException { + return new Registrant[] { + new DirectRegistrar(access,locateDAO,app_name,app_version,port) + }; + } + + public void destroy() { + Cache.stopTimer(); + locateDAO.close(env.newTransNoAvg()); + cluster.close(); + } + + public static void main(final String[] args) { + PropAccess propAccess = new PropAccess(args); + try { + AAF_CM service = new AAF_CM(new AuthzEnv(propAccess)); +// env.setLog4JNames("log4j.properties","authz","cm","audit","init","trace"); + JettyServiceStarter jss = new JettyServiceStarter(service); + jss.start(); + } catch (Exception e) { + e.printStackTrace(); + } + } +} diff --git a/auth/auth-certman/src/main/java/org/onap/aaf/auth/cm/api/API_Artifact.java b/auth/auth-certman/src/main/java/org/onap/aaf/auth/cm/api/API_Artifact.java new file mode 100644 index 00000000..5c067ce1 --- /dev/null +++ b/auth/auth-certman/src/main/java/org/onap/aaf/auth/cm/api/API_Artifact.java @@ -0,0 +1,134 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.cm.api; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.eclipse.jetty.http.HttpStatus; +import org.onap.aaf.auth.cm.AAF_CM; +import org.onap.aaf.auth.cm.mapper.Mapper.API; +import org.onap.aaf.auth.cm.service.Code; +import org.onap.aaf.auth.env.AuthzTrans; +import org.onap.aaf.auth.layer.Result; +import org.onap.aaf.auth.rserv.HttpMethods; + +/** + * API Deployment Artifact Apis.. using Redirect for mechanism + * + * @author Jonathan + * + */ +public class API_Artifact { + private static final String GET_ARTIFACTS = "Get Artifacts"; + + /** + * Normal Init level APIs + * + * @param cmAPI + * @param facade + * @throws Exception + */ + public static void init(final AAF_CM cmAPI) throws Exception { + cmAPI.route(HttpMethods.POST, "/cert/artifacts", API.ARTIFACTS, new Code(cmAPI,"Create Artifacts") { + @Override + public void handle(AuthzTrans trans, HttpServletRequest req, HttpServletResponse resp) throws Exception { + Result r = context.createArtifacts(trans, req, resp); + if(r.isOK()) { + resp.setStatus(HttpStatus.CREATED_201); + } else { + context.error(trans,resp,r); + } + } + }); + + /** + * Use Query Params to get Artifacts by Machine or MechID + */ + cmAPI.route(HttpMethods.GET, "/cert/artifacts", API.ARTIFACTS, new Code(cmAPI,GET_ARTIFACTS) { + @Override + public void handle(AuthzTrans trans, HttpServletRequest req, HttpServletResponse resp) throws Exception { + Result r = context.readArtifacts(trans, req, resp); + if(r.isOK()) { + resp.setStatus(HttpStatus.OK_200); + } else { + context.error(trans,resp,r); + } + } + }); + + + cmAPI.route(HttpMethods.GET, "/cert/artifacts/:mechid/:machine", API.ARTIFACTS, new Code(cmAPI,GET_ARTIFACTS) { + @Override + public void handle(AuthzTrans trans, HttpServletRequest req, HttpServletResponse resp) throws Exception { + + Result r = context.readArtifacts(trans, resp, pathParam(req,":mechid"), pathParam(req,":machine")); + if(r.isOK()) { + resp.setStatus(HttpStatus.OK_200); + } else { + context.error(trans,resp,r); + } + } + }); + + + cmAPI.route(HttpMethods.PUT, "/cert/artifacts", API.ARTIFACTS, new Code(cmAPI,"Update Artifacts") { + @Override + public void handle(AuthzTrans trans, HttpServletRequest req, HttpServletResponse resp) throws Exception { + Result r = context.updateArtifacts(trans, req, resp); + if(r.isOK()) { + resp.setStatus(HttpStatus.OK_200); + } else { + context.error(trans,resp,r); + } + } + }); + + cmAPI.route(HttpMethods.DELETE, "/cert/artifacts/:mechid/:machine", API.VOID, new Code(cmAPI,"Delete Artifacts") { + @Override + public void handle(AuthzTrans trans, HttpServletRequest req, HttpServletResponse resp) throws Exception { + Result r = context.deleteArtifacts(trans, resp, + pathParam(req, ":mechid"), pathParam(req,":machine")); + if(r.isOK()) { + resp.setStatus(HttpStatus.OK_200); + } else { + context.error(trans,resp,r); + } + } + }); + + + cmAPI.route(HttpMethods.DELETE, "/cert/artifacts", API.VOID, new Code(cmAPI,"Delete Artifacts") { + @Override + public void handle(AuthzTrans trans, HttpServletRequest req, HttpServletResponse resp) throws Exception { + Result r = context.deleteArtifacts(trans, req, resp); + if(r.isOK()) { + resp.setStatus(HttpStatus.OK_200); + } else { + context.error(trans,resp,r); + } + } + }); + + + } +} diff --git a/auth/auth-certman/src/main/java/org/onap/aaf/auth/cm/api/API_Cert.java b/auth/auth-certman/src/main/java/org/onap/aaf/auth/cm/api/API_Cert.java new file mode 100644 index 00000000..0cea9c73 --- /dev/null +++ b/auth/auth-certman/src/main/java/org/onap/aaf/auth/cm/api/API_Cert.java @@ -0,0 +1,142 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.cm.api; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.eclipse.jetty.http.HttpStatus; +import org.onap.aaf.auth.cm.AAF_CM; +import org.onap.aaf.auth.cm.ca.CA; +import org.onap.aaf.auth.cm.mapper.Mapper.API; +import org.onap.aaf.auth.cm.service.Code; +import org.onap.aaf.auth.env.AuthzTrans; +import org.onap.aaf.auth.layer.Result; +import org.onap.aaf.auth.rserv.HttpMethods; +import org.onap.aaf.misc.env.Slot; + +/** + * API Apis.. using Redirect for mechanism + * + * @author Jonathan + * + */ +public class API_Cert { + public static final String CERT_AUTH = "CertAuthority"; + private static Slot sCertAuth; + + /** + * Normal Init level APIs + * + * @param aafCM + * @param facade + * @throws Exception + */ + public static void init(final AAF_CM aafCM) throws Exception { + // Check for Created Certificate Authorities in TRANS + sCertAuth = aafCM.env.slot(CERT_AUTH); + + //////// + // Overall APIs + /////// + aafCM.route(HttpMethods.PUT,"/cert/:ca",API.CERT_REQ,new Code(aafCM,"Request Certificate") { + @Override + public void handle(AuthzTrans trans, HttpServletRequest req, HttpServletResponse resp) throws Exception { + String key = pathParam(req, ":ca"); + CA ca; + if((ca = aafCM.getCA(key))==null) { + context.error(trans,resp,Result.ERR_BadData,"CA %s is not supported",key); + } else { + trans.put(sCertAuth, ca); + Result r = context.requestCert(trans, req, resp, ca); + if(r.isOK()) { + resp.setStatus(HttpStatus.OK_200); + } else { + context.error(trans,resp,r); + } + } + } + }); + + aafCM.route(HttpMethods.GET,"/cert/:ca/personal",API.CERT,new Code(aafCM,"Request Personal Certificate") { + @Override + public void handle(AuthzTrans trans, HttpServletRequest req, HttpServletResponse resp) throws Exception { + String key = pathParam(req, ":ca"); + CA ca; + if((ca = aafCM.getCA(key))==null) { + context.error(trans,resp,Result.ERR_BadData,"CA %s is not supported",key); + } else { + trans.put(sCertAuth, ca); + Result r = context.requestPersonalCert(trans, req, resp, ca); + if(r.isOK()) { + resp.setStatus(HttpStatus.OK_200); + } else { + context.error(trans,resp,r); + } + } + } + }); + + + /** + * + */ + aafCM.route(HttpMethods.GET, "/cert/may/:perm", API.VOID, new Code(aafCM,"Check Permission") { + @Override + public void handle(AuthzTrans trans, HttpServletRequest req, HttpServletResponse resp) throws Exception { + Result r = context.check(trans, resp, pathParam(req,"perm")); + if(r.isOK()) { + resp.setStatus(HttpStatus.OK_200); + } else { + trans.checkpoint(r.errorString()); + context.error(trans,resp,Result.err(Result.ERR_Denied,"%s does not have Permission.",trans.user())); + } + } + }); + + /** + * Get Cert by ID and Machine + */ + + + /** + * Get Certs by ID + */ + aafCM.route(HttpMethods.GET, "/cert/id/:id", API.CERT, new Code(aafCM,"GetByID") { + @Override + public void handle(AuthzTrans trans, HttpServletRequest req, HttpServletResponse resp) throws Exception { + Result r = context.readCertsByMechID(trans, resp, pathParam(req,"id")); + if(r.isOK()) { + resp.setStatus(HttpStatus.OK_200); + } else { + context.error(trans,resp,r); + } + } + }); + + + /** + * Get Certs by Machine + */ + + } +} diff --git a/auth/auth-certman/src/main/java/org/onap/aaf/auth/cm/ca/CA.java b/auth/auth-certman/src/main/java/org/onap/aaf/auth/cm/ca/CA.java new file mode 100644 index 00000000..521c5016 --- /dev/null +++ b/auth/auth-certman/src/main/java/org/onap/aaf/auth/cm/ca/CA.java @@ -0,0 +1,209 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ +package org.onap.aaf.auth.cm.ca; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.security.MessageDigest; +import java.security.Principal; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import org.bouncycastle.asn1.x500.style.BCStyle; +import org.onap.aaf.auth.cm.cert.CSRMeta; +import org.onap.aaf.auth.cm.cert.RDN; +import org.onap.aaf.cadi.Access; +import org.onap.aaf.cadi.Access.Level; +import org.onap.aaf.cadi.cm.CertException; +import org.onap.aaf.misc.env.Trans; +import org.onap.aaf.misc.env.util.Split; + +public abstract class CA { + private static final String MUST_EXIST_TO_CREATE_CSRS_FOR = " must exist to create CSRs for "; + //TODO figuring out what is an Issuing CA is a matter of convention. Consider SubClassing for Open Source + public static final String ISSUING_CA = "Issuing CA"; + public static final String CM_CA_PREFIX = "cm_ca."; + public static final String CM_CA_BASE_SUBJECT = ".baseSubject"; + protected static final String CM_PUBLIC_DIR = "cm_public_dir"; + private static final String CM_TRUST_CAS = "cm_trust_cas"; + protected static final String CM_BACKUP_CAS = "cm_backup_cas"; + + public static final Set EMPTY = Collections.unmodifiableSet(new HashSet()); + + + private final String name,env; + private MessageDigest messageDigest; + private final String permType; + private Set caIssuerDNs; + private final ArrayList idDomains; + private String[] trustedCAs; + private List rdns; + + + protected CA(Access access, String caName, String env) throws IOException, CertException { + trustedCAs = new String[4]; // starting array + this.name = caName; + this.env = env; + permType = access.getProperty(CM_CA_PREFIX + name + ".perm_type",null); + if(permType==null) { + throw new CertException(CM_CA_PREFIX + name + ".perm_type" + MUST_EXIST_TO_CREATE_CSRS_FOR + caName); + } + caIssuerDNs = new HashSet(); + + String tag = CA.CM_CA_PREFIX+caName+CA.CM_CA_BASE_SUBJECT; + + String fields = access.getProperty(tag, null); + if(fields==null) { + throw new CertException(tag + MUST_EXIST_TO_CREATE_CSRS_FOR + caName); + } + for(RDN rdn : rdns = RDN.parse('/',fields)) { + if(rdn.aoi==BCStyle.EmailAddress) { // Cert Specs say Emails belong in Subject + throw new CertException("email address is not allowed in " + CM_CA_BASE_SUBJECT); + } + } + + idDomains = new ArrayList(); + StringBuilder sb = null; + for(String s : Split.splitTrim(',', access.getProperty(CA.CM_CA_PREFIX+caName+".idDomains", ""))) { + if(s.length()>0) { + if(sb==null) { + sb = new StringBuilder(); + } else { + sb.append(", "); + } + idDomains.add(s); + sb.append(s); + } + } + if(sb!=null) { + access.printf(Level.INIT, "CA '%s' supports Personal Certificates for %s", caName, sb); + } + + String data_dir = access.getProperty(CM_PUBLIC_DIR,null); + if(data_dir!=null) { + File data = new File(data_dir); + byte[] bytes; + if(data.exists()) { + String trust_cas = access.getProperty(CM_TRUST_CAS,null); + if(trust_cas!=null) { + for(String fname : Split.splitTrim(',', trust_cas)) { + File crt = new File(data,fname); + if(crt.exists()) { + access.printf(Level.INIT, "Loading CA Cert from %s", crt.getAbsolutePath()); + bytes = new byte[(int)crt.length()]; + FileInputStream fis = new FileInputStream(crt); + try { + fis.read(bytes); + addTrustedCA(new String(bytes)); + } finally { + fis.close(); + } + } else { + access.printf(Level.INIT, "FAILED to Load CA Cert from %s", crt.getAbsolutePath()); + } + } + } else { + access.printf(Level.INIT, "Cannot load external TRUST CAs: No property %s",CM_TRUST_CAS); + } + } else { + access.printf(Level.INIT, "Cannot load external TRUST CAs: %s doesn't exist, or is not accessible",data.getAbsolutePath()); + } + } + } + + protected void addCaIssuerDN(String issuerDN) { + caIssuerDNs.add(issuerDN); + } + + protected synchronized void addTrustedCA(final String crtString) { + String crt; + if(crtString.endsWith("\n")) { + crt = crtString; + } else { + crt = crtString + '\n'; + } + for(int i=0;i getCaIssuerDNs() { + return caIssuerDNs; + } + + public String[] getTrustedCAs() { + return trustedCAs; + } + + public String getEnv() { + return env; + } + + protected void setMessageDigest(MessageDigest md) { + messageDigest = md; + } + + /* + * End Required Constructor calls + */ + + public String getName() { + return name; + } + + + public String getPermType() { + return permType; + } + + public abstract X509andChain sign(Trans trans, CSRMeta csrmeta) throws IOException, CertException; + + /* (non-Javadoc) + * @see org.onap.aaf.auth.cm.ca.CA#inPersonalDomains(java.security.Principal) + */ + public boolean inPersonalDomains(Principal p) { + int at = p.getName().indexOf('@'); + if(at>=0) { + return idDomains.contains(p.getName().substring(at+1)); + } else { + return false; + } + } + + public MessageDigest messageDigest() { + return messageDigest; + } + + public CSRMeta newCSRMeta() { + return new CSRMeta(rdns); + } +} diff --git a/auth/auth-certman/src/main/java/org/onap/aaf/auth/cm/ca/JscepCA.java b/auth/auth-certman/src/main/java/org/onap/aaf/auth/cm/ca/JscepCA.java new file mode 100644 index 00000000..ae4e21aa --- /dev/null +++ b/auth/auth-certman/src/main/java/org/onap/aaf/auth/cm/ca/JscepCA.java @@ -0,0 +1,268 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ +package org.onap.aaf.auth.cm.ca; + +import java.io.FileReader; +import java.io.IOException; +import java.net.Authenticator; +import java.net.MalformedURLException; +import java.net.PasswordAuthentication; +import java.net.URL; +import java.security.cert.CertStoreException; +import java.security.cert.Certificate; +import java.security.cert.CertificateException; +import java.security.cert.X509Certificate; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +import org.bouncycastle.operator.OperatorCreationException; +import org.bouncycastle.pkcs.PKCS10CertificationRequest; +import org.jscep.client.Client; +import org.jscep.client.ClientException; +import org.jscep.client.EnrollmentResponse; +import org.jscep.client.verification.CertificateVerifier; +import org.jscep.transaction.TransactionException; +import org.onap.aaf.auth.cm.cert.BCFactory; +import org.onap.aaf.auth.cm.cert.CSRMeta; +import org.onap.aaf.cadi.Access; +import org.onap.aaf.cadi.LocatorException; +import org.onap.aaf.cadi.Access.Level; +import org.onap.aaf.cadi.Locator.Item; +import org.onap.aaf.cadi.cm.CertException; +import org.onap.aaf.cadi.locator.HotPeerLocator; +import org.onap.aaf.misc.env.Env; +import org.onap.aaf.misc.env.TimeTaken; +import org.onap.aaf.misc.env.Trans; +import org.onap.aaf.misc.env.util.Split; + +public class JscepCA extends CA { + static final String CA_PREFIX = "http://"; + static final String CA_POSTFIX="/certsrv/mscep_admin/mscep.dll"; + + private final static String MS_PROFILE="1"; + private final static int MAX_RETRY=3; + public static final long INVALIDATE_TIME = 1000*60*10; // 10 mins + + // package on purpose + private Map mxcwi_s; + private Map mxcwi_c; + + + private JscepClientLocator clients; + + public JscepCA(final Access access, final String name, final String env, String [][] params) throws IOException, CertException, LocatorException { + super(access, name, env); + mxcwi_s = new ConcurrentHashMap(); + mxcwi_c = new ConcurrentHashMap(); + + if(params.length<2) { + throw new CertException("No Trust Chain parameters are included"); + } + if(params[0].length<2) { + throw new CertException("User/Password required for JSCEP"); + } + final String id = params[0][0]; + final String pw = params[0][1]; + + // Set this for NTLM password Microsoft + Authenticator.setDefault(new Authenticator() { + public PasswordAuthentication getPasswordAuthentication () { + try { + return new PasswordAuthentication (id,access.decrypt(pw,true).toCharArray()); + } catch (IOException e) { + access.log(e); + } + return null; + } + }); + + StringBuilder urlstr = new StringBuilder(); + + for(int i=1;i1) { + urlstr.append(','); // delimiter + } + urlstr.append(params[i][0]); + + String dir = access.getProperty(CM_PUBLIC_DIR, ""); + if(!"".equals(dir) && !dir.endsWith("/")) { + dir = dir + '/'; + } + String path; + List frs = new ArrayList(params.length-1); + try { + for(int j=1; j { + + protected JscepClientLocator(Access access, String urlstr)throws LocatorException { + super(access, urlstr, JscepCA.INVALIDATE_TIME, + access.getProperty("cadi_latitude","39.833333"), //Note: Defaulting to GEO center of US + access.getProperty("cadi_longitude","-98.583333") + ); + } + + @Override + protected Client _newClient(String urlinfo) throws LocatorException { + try { + String[] info = Split.split('/', urlinfo); + Client c = new Client(new URL(JscepCA.CA_PREFIX + info[0] + JscepCA.CA_POSTFIX), + new CertificateVerifier() { + @Override + public boolean verify(X509Certificate cert) { + //TODO checkIssuer + return true; + } + } + ); + // Map URL to Client, because Client doesn't expose Connection + mxcwi_c.put(c,mxcwi_s.get(urlinfo)); + return c; + } catch (MalformedURLException e) { + throw new LocatorException(e); + } + } + + @Override + protected Client _invalidate(Client client) { + return null; + } + + @Override + protected void _destroy(Client client) { + mxcwi_c.remove(client); + } + + + } +} diff --git a/auth/auth-certman/src/main/java/org/onap/aaf/auth/cm/ca/LocalCA.java b/auth/auth-certman/src/main/java/org/onap/aaf/auth/cm/ca/LocalCA.java new file mode 100644 index 00000000..b6a2a0a9 --- /dev/null +++ b/auth/auth-certman/src/main/java/org/onap/aaf/auth/cm/ca/LocalCA.java @@ -0,0 +1,182 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ +package org.onap.aaf.auth.cm.ca; + +import java.io.File; +import java.io.FileReader; +import java.io.IOException; +import java.math.BigInteger; +import java.security.GeneralSecurityException; +import java.security.SecureRandom; +import java.security.cert.X509Certificate; +import java.security.interfaces.RSAPrivateKey; +import java.security.interfaces.RSAPublicKey; +import java.util.ArrayList; +import java.util.Date; +import java.util.GregorianCalendar; +import java.util.List; + +import org.bouncycastle.asn1.x500.X500Name; +import org.bouncycastle.asn1.x500.X500NameBuilder; +import org.bouncycastle.asn1.x509.BasicConstraints; +import org.bouncycastle.asn1.x509.ExtendedKeyUsage; +import org.bouncycastle.asn1.x509.Extension; +import org.bouncycastle.asn1.x509.GeneralName; +import org.bouncycastle.asn1.x509.GeneralNames; +import org.bouncycastle.asn1.x509.KeyPurposeId; +import org.bouncycastle.asn1.x509.KeyUsage; +import org.bouncycastle.cert.X509v3CertificateBuilder; +import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter; +import org.bouncycastle.cert.jcajce.JcaX509ExtensionUtils; +import org.bouncycastle.crypto.params.RSAKeyParameters; +import org.bouncycastle.crypto.util.SubjectPublicKeyInfoFactory; +import org.bouncycastle.operator.OperatorCreationException; +import org.onap.aaf.auth.cm.cert.BCFactory; +import org.onap.aaf.auth.cm.cert.CSRMeta; +import org.onap.aaf.auth.cm.cert.RDN; +import org.onap.aaf.auth.env.NullTrans; +import org.onap.aaf.cadi.Access; +import org.onap.aaf.cadi.Access.Level; +import org.onap.aaf.cadi.cm.CertException; +import org.onap.aaf.cadi.cm.Factory; +import org.onap.aaf.misc.env.Env; +import org.onap.aaf.misc.env.TimeTaken; +import org.onap.aaf.misc.env.Trans; + +public class LocalCA extends CA { + + // Extensions + private static final KeyPurposeId[] ASN_WebUsage = new KeyPurposeId[] { + KeyPurposeId.id_kp_serverAuth, // WebServer + KeyPurposeId.id_kp_clientAuth};// WebClient + + private final RSAPrivateKey caKey; + private final X500Name issuer; + private final SecureRandom random = new SecureRandom(); + private byte[] serialish; + private final X509ChainWithIssuer x509cwi; // "Cert" is CACert + + public LocalCA(Access access, final String name, final String env, final String[][] params) throws IOException, CertException { + super(access, name, env); + serialish = new byte[24]; + if(params.length<1 || params[0].length<2) { + throw new IOException("LocalCA expects cm_ca.=org.onap.aaf.auth.cm.ca.LocalCA,[;]+"); + } + + // Read in the Private Key + File f = new File(params[0][0]); // key + if(f.exists()) { + caKey = (RSAPrivateKey)Factory.toPrivateKey(NullTrans.singleton(),f); + } else { + throw new CertException("Private Key, " + f.getPath() + ", does not exist"); + } + + String dir = access.getProperty(CM_PUBLIC_DIR, ""); + if(!"".equals(dir) && !dir.endsWith("/")) { + dir = dir + '/'; + } + List frs = new ArrayList(params.length-1); + try { + String path; + for(int i=1; i lsan = new ArrayList(); + for(String s : csrmeta.sans()) { + lsan.add(new GeneralName(GeneralName.dNSName,s)); + } + GeneralName[] sans = new GeneralName[lsan.size()]; + lsan.toArray(sans); + + JcaX509ExtensionUtils extUtils = new JcaX509ExtensionUtils(); + xcb.addExtension(Extension.basicConstraints, + false, new BasicConstraints(false)) + .addExtension(Extension.keyUsage, + true, new KeyUsage(KeyUsage.digitalSignature + | KeyUsage.keyEncipherment)) + .addExtension(Extension.extendedKeyUsage, + true, new ExtendedKeyUsage(ASN_WebUsage)) + + .addExtension(Extension.authorityKeyIdentifier, + false, extUtils.createAuthorityKeyIdentifier(x509cwi.cert)) + .addExtension(Extension.subjectKeyIdentifier, + false, extUtils.createSubjectKeyIdentifier(x509cwi.cert.getPublicKey())) + .addExtension(Extension.subjectAlternativeName, + false, new GeneralNames(sans)) + ; + + x509 = new JcaX509CertificateConverter().getCertificate( + xcb.build(BCFactory.contentSigner(caKey))); + } catch (GeneralSecurityException|OperatorCreationException e) { + throw new CertException(e); + } finally { + tt.done(); + } + + return new X509ChainWithIssuer(x509cwi,x509); + } + +} diff --git a/auth/auth-certman/src/main/java/org/onap/aaf/auth/cm/ca/X509ChainWithIssuer.java b/auth/auth-certman/src/main/java/org/onap/aaf/auth/cm/ca/X509ChainWithIssuer.java new file mode 100644 index 00000000..e0a85676 --- /dev/null +++ b/auth/auth-certman/src/main/java/org/onap/aaf/auth/cm/ca/X509ChainWithIssuer.java @@ -0,0 +1,74 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ +package org.onap.aaf.auth.cm.ca; + +import java.io.IOException; +import java.io.Reader; +import java.security.Principal; +import java.security.cert.Certificate; +import java.security.cert.CertificateException; +import java.security.cert.X509Certificate; +import java.util.Collection; +import java.util.List; + +import org.onap.aaf.cadi.cm.CertException; +import org.onap.aaf.cadi.cm.Factory; + +public class X509ChainWithIssuer extends X509andChain { + private String issuerDN; + + public X509ChainWithIssuer(X509ChainWithIssuer orig, X509Certificate x509) { + super(x509,orig.trustChain); + issuerDN=orig.issuerDN; + } + + public X509ChainWithIssuer(final List rdrs) throws IOException, CertException { + // Trust Chain. Last one should be the CA + Collection certs; + X509Certificate x509; + for(Reader rdr : rdrs) { + if(rdr!=null) { // cover for badly formed array + byte[] bytes = Factory.decode(rdr); + try { + certs = Factory.toX509Certificate(bytes); + } catch (CertificateException e) { + throw new CertException(e); + } + for(Certificate c : certs) { + x509=(X509Certificate)c; + Principal subject = x509.getSubjectDN(); + if(subject!=null) { + if(cert==null) { // first in Trust Chain + issuerDN= subject.toString(); + } + addTrustChainEntry(x509); + cert=x509; // adding each time makes sure last one is signer. + } + } + } + } + } + + public String getIssuerDN() { + return issuerDN; + } + +} \ No newline at end of file diff --git a/auth/auth-certman/src/main/java/org/onap/aaf/auth/cm/ca/X509andChain.java b/auth/auth-certman/src/main/java/org/onap/aaf/auth/cm/ca/X509andChain.java new file mode 100644 index 00000000..24416c92 --- /dev/null +++ b/auth/auth-certman/src/main/java/org/onap/aaf/auth/cm/ca/X509andChain.java @@ -0,0 +1,79 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ +package org.onap.aaf.auth.cm.ca; + +import java.io.IOException; +import java.security.cert.X509Certificate; +import java.util.List; + +import org.onap.aaf.auth.env.NullTrans; +import org.onap.aaf.cadi.cm.CertException; +import org.onap.aaf.cadi.cm.Factory; + + +/** + * Have to put the Cert and resulting Trust Chain together. + * Treating them separately has caused issues + * + * @author jg1555 + * + */ +public class X509andChain { + protected X509Certificate cert; + protected String[] trustChain; + + public X509andChain() { + cert = null; + trustChain = null; + } + + public X509andChain(X509Certificate cert, String[] trustChain) { + this.cert = cert; + this.trustChain = trustChain; + } + + public X509andChain(X509Certificate cert, List chain) { + this.cert = cert; + trustChain = new String[chain.size()]; + chain.toArray(trustChain); + } + + + public void addTrustChainEntry(X509Certificate x509) throws IOException, CertException { + if(trustChain==null) { + trustChain = new String[] {Factory.toString(NullTrans.singleton(),x509)}; + } else { + String[] temp = new String[trustChain.length+1]; + System.arraycopy(trustChain, 0, temp, 0, trustChain.length); + temp[trustChain.length]=Factory.toString(NullTrans.singleton(),x509); + trustChain=temp; + } + } + + public X509Certificate getX509() { + return cert; + } + + public String[] getTrustChain() { + return trustChain; + } + +} diff --git a/auth/auth-certman/src/main/java/org/onap/aaf/auth/cm/cert/BCFactory.java b/auth/auth-certman/src/main/java/org/onap/aaf/auth/cm/cert/BCFactory.java new file mode 100644 index 00000000..4fdac6a6 --- /dev/null +++ b/auth/auth-certman/src/main/java/org/onap/aaf/auth/cm/cert/BCFactory.java @@ -0,0 +1,151 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ +package org.onap.aaf.auth.cm.cert; + +import java.io.File; +import java.io.FileReader; +import java.io.IOException; +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; +import java.security.PrivateKey; +import java.security.SignatureException; +import java.util.List; + +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.operator.ContentSigner; +import org.bouncycastle.operator.OperatorCreationException; +import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder; +import org.bouncycastle.pkcs.PKCS10CertificationRequest; +import org.onap.aaf.auth.cm.ca.CA; +import org.onap.aaf.auth.cm.validation.CertmanValidator; +import org.onap.aaf.cadi.Symm; +import org.onap.aaf.cadi.cm.CertException; +import org.onap.aaf.cadi.cm.Factory; +import org.onap.aaf.misc.env.Env; +import org.onap.aaf.misc.env.TimeTaken; +import org.onap.aaf.misc.env.Trans; + + +/** + * Additional Factory mechanisms for CSRs, and BouncyCastle. The main Factory + * utilizes only Java abstractions, and is useful in Client code. + * + * @author jg1555 + * + */ +public class BCFactory extends Factory { + private static final JcaContentSignerBuilder jcsb; + + + static { + // Bouncy + jcsb = new JcaContentSignerBuilder(Factory.SIG_ALGO); + } + + public static ContentSigner contentSigner(PrivateKey pk) throws OperatorCreationException { + return jcsb.build(pk); + } + + public static String toString(PKCS10CertificationRequest csr) throws IOException, CertException { + if(csr==null) { + throw new CertException("x509 Certificate Request not built"); + } + return textBuilder("CERTIFICATE REQUEST",csr.getEncoded()); + } + + public static PKCS10CertificationRequest toCSR(Trans trans, File file) throws IOException { + TimeTaken tt = trans.start("Reconstitute CSR", Env.SUB); + try { + FileReader fr = new FileReader(file); + return new PKCS10CertificationRequest(decode(strip(fr))); + } finally { + tt.done(); + } + } + + public static byte[] sign(Trans trans, ASN1Object toSign, PrivateKey pk) throws IOException, InvalidKeyException, SignatureException, NoSuchAlgorithmException { + TimeTaken tt = trans.start("Encode Security Object", Env.SUB); + try { + return sign(trans,toSign.getEncoded(),pk); + } finally { + tt.done(); + } + } + + public static CSRMeta createCSRMeta(CA ca, String mechid, String sponsorEmail, List fqdns) throws CertException { + CSRMeta csr = ca.newCSRMeta(); + boolean first = true; + // Set CN (and SAN) + for(String fqdn : fqdns) { + if(first) { + first = false; + csr.cn(fqdn); + } + csr.san(fqdn); // duplicate CN in SAN, per RFC 5280 section 4.2.1.6 + } + + csr.challenge(new String(Symm.randomGen(24))); + csr.mechID(mechid); + csr.email(sponsorEmail); + String errs; + if((errs=validateApp(csr))!=null) { + throw new CertException(errs); + } + return csr; + } + + private static String validateApp(CSRMeta csr) { + CertmanValidator v = new CertmanValidator(); + if(v.nullOrBlank("cn", csr.cn()) + .nullOrBlank("mechID", csr.mechID()) + .nullOrBlank("email", csr.email()) + .err()) { + return v.errs(); + } else { + return null; + } + } + + public static CSRMeta createPersonalCSRMeta(CA ca, String personal, String email) throws CertException { + CSRMeta csr = ca.newCSRMeta(); + csr.cn(personal); + csr.challenge(new String(Symm.randomGen(24))); + csr.email(email); + String errs; + if((errs=validatePersonal(csr))!=null) { + throw new CertException(errs); + } + return csr; + } + + private static String validatePersonal(CSRMeta csr) { + CertmanValidator v = new CertmanValidator(); + if(v.nullOrBlank("cn", csr.cn()) + .nullOrBlank("email", csr.email()) + .err()) { + return v.errs(); + } else { + return null; + } + } + + +} diff --git a/auth/auth-certman/src/main/java/org/onap/aaf/auth/cm/cert/CSRMeta.java b/auth/auth-certman/src/main/java/org/onap/aaf/auth/cm/cert/CSRMeta.java new file mode 100644 index 00000000..2541bea0 --- /dev/null +++ b/auth/auth-certman/src/main/java/org/onap/aaf/auth/cm/cert/CSRMeta.java @@ -0,0 +1,266 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ +package org.onap.aaf.auth.cm.cert; + +import java.io.IOException; +import java.math.BigInteger; +import java.security.KeyPair; +import java.security.SecureRandom; +import java.security.cert.CertificateException; +import java.security.cert.X509Certificate; +import java.util.ArrayList; +import java.util.Date; +import java.util.GregorianCalendar; +import java.util.List; + +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.DERPrintableString; +import org.bouncycastle.asn1.pkcs.Attribute; +import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; +import org.bouncycastle.asn1.x500.X500Name; +import org.bouncycastle.asn1.x500.X500NameBuilder; +import org.bouncycastle.asn1.x500.style.BCStyle; +import org.bouncycastle.asn1.x509.Extension; +import org.bouncycastle.asn1.x509.Extensions; +import org.bouncycastle.asn1.x509.GeneralName; +import org.bouncycastle.asn1.x509.GeneralNames; +import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; +import org.bouncycastle.cert.X509v3CertificateBuilder; +import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter; +import org.bouncycastle.operator.OperatorCreationException; +import org.bouncycastle.pkcs.PKCS10CertificationRequest; +import org.bouncycastle.pkcs.PKCS10CertificationRequestBuilder; +import org.bouncycastle.pkcs.jcajce.JcaPKCS10CertificationRequestBuilder; +import org.onap.aaf.cadi.cm.CertException; +import org.onap.aaf.cadi.cm.Factory; +import org.onap.aaf.misc.env.Trans; + +public class CSRMeta { + private String cn; + private String mechID; + private String environment; + private String email; + private String challenge; + private List rdns; + + public CSRMeta(List rdns) { + this.rdns = rdns; + } + + private ArrayList sanList = new ArrayList(); + private KeyPair keyPair; + private X500Name name = null; + private SecureRandom random = new SecureRandom(); + + public X500Name x500Name() throws IOException { + if(name==null) { + X500NameBuilder xnb = new X500NameBuilder(); + xnb.addRDN(BCStyle.CN,cn); + xnb.addRDN(BCStyle.E,email); + if(mechID!=null) { + if(environment==null) { + xnb.addRDN(BCStyle.OU,mechID); + } else { + xnb.addRDN(BCStyle.OU,mechID+':'+environment); + } + } + for(RDN rdn : rdns) { + xnb.addRDN(rdn.aoi,rdn.value); + } + name = xnb.build(); + } + return name; + } + + + public PKCS10CertificationRequest generateCSR(Trans trans) throws IOException, CertException { + PKCS10CertificationRequestBuilder builder = new JcaPKCS10CertificationRequestBuilder(x500Name(),keypair(trans).getPublic()); + if(challenge!=null) { + DERPrintableString password = new DERPrintableString(challenge); + builder.addAttribute(PKCSObjectIdentifiers.pkcs_9_at_challengePassword, password); + } + + int plus = email==null?0:1; + if(sanList.size()>0) { + GeneralName[] gna = new GeneralName[sanList.size()+plus]; + int i=-1; + for(String s : sanList) { + gna[++i]=new GeneralName(GeneralName.dNSName,s); + } + gna[++i]=new GeneralName(GeneralName.rfc822Name,email); + + builder.addAttribute( + PKCSObjectIdentifiers.pkcs_9_at_extensionRequest, + new Extensions(new Extension[] { + new Extension(Extension.subjectAlternativeName,false,new GeneralNames(gna).getEncoded()) + }) + ); + } + + if(email!=null) { + + } + try { + return builder.build(BCFactory.contentSigner(keypair(trans).getPrivate())); + } catch (OperatorCreationException e) { + throw new CertException(e); + } + } + + @SuppressWarnings("deprecation") + public static void dump(PKCS10CertificationRequest csr) { + Attribute[] certAttributes = csr.getAttributes(); + for (Attribute attribute : certAttributes) { + if (attribute.getAttrType().equals(PKCSObjectIdentifiers.pkcs_9_at_extensionRequest)) { + Extensions extensions = Extensions.getInstance(attribute.getAttrValues().getObjectAt(0)); + GeneralNames gns = GeneralNames.fromExtensions(extensions,Extension.subjectAlternativeName); + GeneralName[] names = gns.getNames(); + for(int k=0; k < names.length; k++) { + String title = ""; + if(names[k].getTagNo() == GeneralName.dNSName) { + title = "dNSName"; + } else if(names[k].getTagNo() == GeneralName.iPAddress) { + title = "iPAddress"; + // Deprecated, but I don't see anything better to use. + names[k].toASN1Object(); + } else if(names[k].getTagNo() == GeneralName.otherName) { + title = "otherName"; + } else if(names[k].getTagNo() == GeneralName.rfc822Name) { + title = "email"; + } + + System.out.println(title + ": "+ names[k].getName()); + } + } + } + } + + public X509Certificate initialConversationCert(Trans trans) throws IOException, CertificateException, OperatorCreationException { + GregorianCalendar gc = new GregorianCalendar(); + Date start = gc.getTime(); + gc.add(GregorianCalendar.DAY_OF_MONTH,2); + Date end = gc.getTime(); + X509v3CertificateBuilder xcb = new X509v3CertificateBuilder( + x500Name(), + new BigInteger(12,random), // replace with Serialnumber scheme + start, + end, + x500Name(), + new SubjectPublicKeyInfo(ASN1Sequence.getInstance(keypair(trans).getPublic().getEncoded())) + ); + return new JcaX509CertificateConverter().getCertificate( + xcb.build(BCFactory.contentSigner(keypair(trans).getPrivate()))); + } + + public CSRMeta san(String v) { + sanList.add(v); + return this; + } + + public List sans() { + return sanList; + } + + + public KeyPair keypair(Trans trans) { + if(keyPair == null) { + keyPair = Factory.generateKeyPair(trans); + } + return keyPair; + } + + /** + * @return the cn + */ + public String cn() { + return cn; + } + + + /** + * @param cn the cn to set + */ + public void cn(String cn) { + this.cn = cn; + } + + /** + * Environment of Service MechID is good for + */ + public void environment(String env) { + environment = env; + } + + /** + * + * @return + */ + public String environment() { + return environment; + } + + /** + * @return the mechID + */ + public String mechID() { + return mechID; + } + + + /** + * @param mechID the mechID to set + */ + public void mechID(String mechID) { + this.mechID = mechID; + } + + + /** + * @return the email + */ + public String email() { + return email; + } + + + /** + * @param email the email to set + */ + public void email(String email) { + this.email = email; + } + + /** + * @return the challenge + */ + public String challenge() { + return challenge; + } + + + /** + * @param challenge the challenge to set + */ + public void challenge(String challenge) { + this.challenge = challenge; + } + +} diff --git a/auth/auth-certman/src/main/java/org/onap/aaf/auth/cm/cert/RDN.java b/auth/auth-certman/src/main/java/org/onap/aaf/auth/cm/cert/RDN.java new file mode 100644 index 00000000..7d4161f2 --- /dev/null +++ b/auth/auth-certman/src/main/java/org/onap/aaf/auth/cm/cert/RDN.java @@ -0,0 +1,101 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ +package org.onap.aaf.auth.cm.cert; + +import java.util.ArrayList; +import java.util.List; + +import org.bouncycastle.asn1.ASN1ObjectIdentifier; +import org.bouncycastle.asn1.x500.style.BCStyle; +import org.onap.aaf.cadi.cm.CertException; +import org.onap.aaf.cadi.util.Split; + +public class RDN { + public String tag; + public String value; + public ASN1ObjectIdentifier aoi; + public RDN(final String tagValue) throws CertException { + String[] tv = Split.splitTrim('=',tagValue); + switch(tv[0]) { + case "cn":case "CN": aoi = BCStyle.CN; break; + case "c":case "C": aoi = BCStyle.C;break; + case "st":case "ST": aoi = BCStyle.ST;break; + case "l":case "L": aoi = BCStyle.L;break; + case "o":case "O": aoi = BCStyle.O;break; + case "ou":case "OU": aoi = BCStyle.OU;break; + case "dc":case "DC": aoi = BCStyle.DC;break; + case "gn":case "GN": aoi = BCStyle.GIVENNAME; break; + case "sn":case "SN": aoi = BCStyle.SN; break; // surname + case "email":case "EMAIL": + case "emailaddress": + case "EMAILADDRESS": aoi = BCStyle.EmailAddress;break; // should be SAN extension + case "initials": aoi = BCStyle.INITIALS; break; + case "pseudonym": aoi = BCStyle.PSEUDONYM; break; + case "generationQualifier": aoi = BCStyle.GENERATION; break; + case "serialNumber": aoi = BCStyle.SERIALNUMBER; break; + default: + throw new CertException("Unknown ASN1ObjectIdentifier for " + tv[0]); + } + tag = tv[0]; + value = tv[1]; + } + + /** + * Parse various forms of DNs into appropriate RDNs, which have the ASN1ObjectIdentifier + * @param delim + * @param dnString + * @return + * @throws CertException + */ + public static List parse(final char delim, final String dnString ) throws CertException { + List lrnd = new ArrayList(); + StringBuilder sb = new StringBuilder(); + boolean inQuotes = false; + for(int i=0;i fqdns; + // Notify + public List emails; + + + // These may be null + public String sponsor; + public XMLGregorianCalendar start, end; + + public CSRMeta getCSRMeta() throws CertException { + return BCFactory.createCSRMeta(certAuthority, mechid, sponsor,fqdns); + } +} diff --git a/auth/auth-certman/src/main/java/org/onap/aaf/auth/cm/data/CertResp.java b/auth/auth-certman/src/main/java/org/onap/aaf/auth/cm/data/CertResp.java new file mode 100644 index 00000000..595025e7 --- /dev/null +++ b/auth/auth-certman/src/main/java/org/onap/aaf/auth/cm/data/CertResp.java @@ -0,0 +1,94 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.cm.data; + +import java.io.IOException; +import java.security.GeneralSecurityException; +import java.security.KeyPair; +import java.security.cert.X509Certificate; +import java.util.Set; + +import org.onap.aaf.auth.cm.ca.CA; +import org.onap.aaf.auth.cm.cert.CSRMeta; +import org.onap.aaf.cadi.cm.CertException; +import org.onap.aaf.cadi.cm.Factory; +import org.onap.aaf.misc.env.Trans; + +public class CertResp { + private CA ca; + private KeyPair keyPair; + private String challenge; + + private String privateKey, certString; + private String[] trustChain; + private String[] trustCAs; + private String[] notes; + + public CertResp(Trans trans, CA ca, X509Certificate x509, CSRMeta csrMeta, String[] trustChain, String[] trustCAs, String[] notes) throws IOException, GeneralSecurityException, CertException { + keyPair = csrMeta.keypair(trans); + privateKey = Factory.toString(trans, keyPair.getPrivate()); + certString = Factory.toString(trans,x509); + challenge=csrMeta.challenge(); + this.ca = ca; + this.trustChain = trustChain; + this.trustCAs = trustCAs; + this.notes = notes; + } + + // Use for Read Responses, etc + public CertResp(String cert) { + certString = cert; + } + + + public String asCertString() { + return certString; + } + + public String privateString() throws IOException { + return privateKey; + } + + public String challenge() { + return challenge==null?"":challenge; + } + + public String[] notes() { + return notes; + } + + public Set caIssuerDNs() { + return ca.getCaIssuerDNs(); + } + + public String env() { + return ca.getEnv(); + } + + public String[] trustChain() { + return trustChain; + } + + public String[] trustCAs() { + return trustCAs; + } +} diff --git a/auth/auth-certman/src/main/java/org/onap/aaf/auth/cm/facade/Facade.java b/auth/auth-certman/src/main/java/org/onap/aaf/auth/cm/facade/Facade.java new file mode 100644 index 00000000..9eb9c2fa --- /dev/null +++ b/auth/auth-certman/src/main/java/org/onap/aaf/auth/cm/facade/Facade.java @@ -0,0 +1,182 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.cm.facade; + +import java.io.IOException; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.onap.aaf.auth.cm.ca.CA; +import org.onap.aaf.auth.cm.mapper.Mapper; +import org.onap.aaf.auth.env.AuthzTrans; +import org.onap.aaf.auth.layer.Result; + + +/** + * + * @author Jonathan + * + */ +public interface Facade { + +///////////////////// STANDARD ELEMENTS ////////////////// + /** + * @param trans + * @param response + * @param result + */ + void error(AuthzTrans trans, HttpServletResponse response, Result result); + + /** + * + * @param trans + * @param response + * @param status + */ + void error(AuthzTrans trans, HttpServletResponse response, int status, String msg, String ... detail); + + /** + * Permission checker + * + * @param trans + * @param resp + * @param perm + * @return + * @throws IOException + */ + Result check(AuthzTrans trans, HttpServletResponse resp, String perm) throws IOException; + + /** + * + * @return + */ + public Mapper mapper(); + +///////////////////// STANDARD ELEMENTS ////////////////// + + /** + * + * @param trans + * @param resp + * @param rservlet + * @return + */ + public abstract Result requestCert(AuthzTrans trans, HttpServletRequest req, HttpServletResponse resp, CA ca); + + /** + * + * @param trans + * @param resp + * @param rservlet + * @return + */ + public abstract Result requestPersonalCert(AuthzTrans trans, HttpServletRequest req, HttpServletResponse resp, CA ca); + + + /** + * + * @param trans + * @param req + * @param resp + * @return + */ + public abstract Result renewCert(AuthzTrans trans, HttpServletRequest req, HttpServletResponse resp, boolean withTrust); + + /** + * + * @param trans + * @param req + * @param resp + * @return + */ + public abstract Result dropCert(AuthzTrans trans, HttpServletRequest req, HttpServletResponse resp); + + + /** + * + * @param trans + * @param resp + * @param pathParam + * @return + */ + public Result readCertsByMechID(AuthzTrans trans, HttpServletResponse resp, String mechID); + + + /** + * + * @param trans + * @param req + * @param resp + * @return + */ + Result createArtifacts(AuthzTrans trans, HttpServletRequest req, HttpServletResponse resp); + + /** + * + * @param trans + * @param req + * @param resp + * @return + */ + Result readArtifacts(AuthzTrans trans, HttpServletRequest req, HttpServletResponse resp); + + /** + * + * @param trans + * @param resp + * @param mechid + * @param machine + * @return + */ + Result readArtifacts(AuthzTrans trans, HttpServletResponse resp, String mechid, String machine); + + /** + * + * @param trans + * @param req + * @param resp + * @return + */ + Result updateArtifacts(AuthzTrans trans, HttpServletRequest req, HttpServletResponse resp); + + /** + * + * @param trans + * @param req + * @param resp + * @return + */ + Result deleteArtifacts(AuthzTrans trans, HttpServletRequest req, HttpServletResponse resp); + + /** + * + * @param trans + * @param resp + * @param mechid + * @param machine + * @return + */ + Result deleteArtifacts(AuthzTrans trans, HttpServletResponse resp, String mechid, String machine); + + +} \ No newline at end of file diff --git a/auth/auth-certman/src/main/java/org/onap/aaf/auth/cm/facade/Facade1_0.java b/auth/auth-certman/src/main/java/org/onap/aaf/auth/cm/facade/Facade1_0.java new file mode 100644 index 00000000..49d976b2 --- /dev/null +++ b/auth/auth-certman/src/main/java/org/onap/aaf/auth/cm/facade/Facade1_0.java @@ -0,0 +1,46 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.cm.facade; + +import org.onap.aaf.auth.cm.AAF_CM; +import org.onap.aaf.auth.cm.mapper.Mapper; +import org.onap.aaf.auth.cm.service.CMService; +import org.onap.aaf.misc.env.APIException; +import org.onap.aaf.misc.env.Data; + +import aaf.v2_0.Error; +import certman.v1_0.Artifacts; +import certman.v1_0.BaseRequest; +import certman.v1_0.CertInfo; + +/** + * @author Jonathan + * + */ +public class Facade1_0 extends FacadeImpl { + public Facade1_0(AAF_CM certman, + CMService service, + Mapper mapper, + Data.TYPE type) throws APIException { + super(certman, service, mapper, type); + } +} diff --git a/auth/auth-certman/src/main/java/org/onap/aaf/auth/cm/facade/FacadeFactory.java b/auth/auth-certman/src/main/java/org/onap/aaf/auth/cm/facade/FacadeFactory.java new file mode 100644 index 00000000..6eb13f93 --- /dev/null +++ b/auth/auth-certman/src/main/java/org/onap/aaf/auth/cm/facade/FacadeFactory.java @@ -0,0 +1,41 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.cm.facade; + +import org.onap.aaf.auth.cm.AAF_CM; +import org.onap.aaf.auth.cm.mapper.Mapper1_0; +import org.onap.aaf.auth.cm.service.CMService; +import org.onap.aaf.auth.env.AuthzTrans; +import org.onap.aaf.misc.env.APIException; +import org.onap.aaf.misc.env.Data; + + +public class FacadeFactory { + public static Facade1_0 v1_0(AAF_CM certman, AuthzTrans trans, CMService service, Data.TYPE type) throws APIException { + return new Facade1_0( + certman, + service, + new Mapper1_0(), + type); + } + +} diff --git a/auth/auth-certman/src/main/java/org/onap/aaf/auth/cm/facade/FacadeImpl.java b/auth/auth-certman/src/main/java/org/onap/aaf/auth/cm/facade/FacadeImpl.java new file mode 100644 index 00000000..0598ee60 --- /dev/null +++ b/auth/auth-certman/src/main/java/org/onap/aaf/auth/cm/facade/FacadeImpl.java @@ -0,0 +1,643 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.cm.facade; + +import static org.onap.aaf.auth.layer.Result.ERR_ActionNotCompleted; +import static org.onap.aaf.auth.layer.Result.ERR_BadData; +import static org.onap.aaf.auth.layer.Result.ERR_ConflictAlreadyExists; +import static org.onap.aaf.auth.layer.Result.ERR_Denied; +import static org.onap.aaf.auth.layer.Result.ERR_NotFound; +import static org.onap.aaf.auth.layer.Result.ERR_NotImplemented; +import static org.onap.aaf.auth.layer.Result.ERR_Policy; +import static org.onap.aaf.auth.layer.Result.ERR_Security; +import static org.onap.aaf.auth.layer.Result.OK; + +import java.io.IOException; +import java.security.KeyStore; +import java.security.KeyStoreException; +import java.security.NoSuchAlgorithmException; +import java.security.PrivateKey; +import java.security.cert.Certificate; +import java.security.cert.CertificateException; +import java.security.cert.X509Certificate; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.onap.aaf.auth.cm.AAF_CM; +import org.onap.aaf.auth.cm.ca.CA; +import org.onap.aaf.auth.cm.data.CertResp; +import org.onap.aaf.auth.cm.mapper.Mapper; +import org.onap.aaf.auth.cm.mapper.Mapper.API; +import org.onap.aaf.auth.cm.service.CMService; +import org.onap.aaf.auth.dao.cass.ArtiDAO; +import org.onap.aaf.auth.dao.cass.Status; +import org.onap.aaf.auth.env.AuthzEnv; +import org.onap.aaf.auth.env.AuthzTrans; +import org.onap.aaf.auth.layer.Result; +import org.onap.aaf.cadi.aaf.AAFPermission; +import org.onap.aaf.cadi.cm.CertException; +import org.onap.aaf.cadi.cm.Factory; +import org.onap.aaf.misc.env.APIException; +import org.onap.aaf.misc.env.Data; +import org.onap.aaf.misc.env.Env; +import org.onap.aaf.misc.env.TimeTaken; +import org.onap.aaf.misc.env.util.Split; +import org.onap.aaf.misc.rosetta.env.RosettaDF; +import org.onap.aaf.misc.rosetta.env.RosettaData; + +/** + * AuthzFacade + * + * This Service Facade encapsulates the essence of the API Service can do, and provides + * a single created object for elements such as RosettaDF. + * + * The Responsibilities of this class are to: + * 1) Interact with the Service Implementation (which might be supported by various kinds of Backend Storage) + * 2) Validate incoming data (if applicable) + * 3) Convert the Service response into the right Format, and mark the Content Type + * a) In the future, we may support multiple Response Formats, aka JSON or XML, based on User Request. + * 4) Log Service info, warnings and exceptions as necessary + * 5) When asked by the API layer, this will create and write Error content to the OutputStream + * + * Note: This Class does NOT set the HTTP Status Code. That is up to the API layer, so that it can be + * clearly coordinated with the API Documentation + * + * @author Jonathan + * + */ +public abstract class FacadeImpl extends org.onap.aaf.auth.layer.FacadeImpl implements Facade + { + private static final String TRUE = "TRUE"; + private static final String REQUEST_CERT = "Request New Certificate"; + private static final String RENEW_CERT = "Renew Certificate"; + private static final String DROP_CERT = "Drop Certificate"; + private static final String READ_CERTS_MECHID = "Read Certificates by MechID"; + private static final String CREATE_ARTIFACTS = "Create Deployment Artifact"; + private static final String READ_ARTIFACTS = "Read Deployment Artifact"; + private static final String UPDATE_ARTIFACTS = "Update Deployment Artifact"; + private static final String DELETE_ARTIFACTS = "Delete Deployment Artifact"; + + private CMService service; + + private final RosettaDF errDF; + private final RosettaDF certRequestDF, certRenewDF, certDropDF; + private final RosettaDF certDF; + private final RosettaDF artiDF; + private Mapper mapper; +// private Slot sCertAuth; + private AAF_CM certman; + private final String voidResp; + + public FacadeImpl(AAF_CM certman, + CMService service, + Mapper mapper, + Data.TYPE dataType) throws APIException { + this.service = service; + this.mapper = mapper; + this.certman = certman; + AuthzEnv env = certman.env; + //TODO: Gabe [JUnit] Static issue, talk to Jonathan + (errDF = env.newDataFactory(mapper.getClass(API.ERROR))).in(dataType).out(dataType); + (certRequestDF = env.newDataFactory(mapper.getClass(API.CERT_REQ))).in(dataType).out(dataType); + (certRenewDF = env.newDataFactory(mapper.getClass(API.CERT_RENEW))).in(dataType).out(dataType); + (certDropDF = env.newDataFactory(mapper.getClass(API.CERT_DROP))).in(dataType).out(dataType); + (certDF = env.newDataFactory(mapper.getClass(API.CERT))).in(dataType).out(dataType); + (artiDF = env.newDataFactory(mapper.getClass(API.ARTIFACTS))).in(dataType).out(dataType); +// sCertAuth = env.slot(API_Cert.CERT_AUTH); + if(artiDF.getOutType().name().contains("xml")) { + voidResp = "application/Void+xml;charset=utf-8;version=1.0,application/xml;version=1.0,*/*"; + } else { + voidResp = "application/Void+json;charset=utf-8;version=1.0,application/json;version=1.0,*/*"; + } + } + + public Mapper mapper() { + return mapper; + } + + /* (non-Javadoc) + * @see com.att.authz.facade.AuthzFacade#error(org.onap.aaf.auth.env.test.AuthzTrans, javax.servlet.http.HttpServletResponse, int) + * + * Note: Conforms to AT&T TSS RESTful Error Structure + */ + @Override + public void error(AuthzTrans trans, HttpServletResponse response, Result result) { + error(trans, response, result.status, + result.details==null?"":result.details.trim(), + result.variables==null?new String[0]:result.variables); + } + + @Override + public void error(AuthzTrans trans, HttpServletResponse response, int status, final String _msg, final String ... _detail) { + String msgId; + String prefix; + boolean hidemsg=false; + switch(status) { + case 202: + case ERR_ActionNotCompleted: + msgId = "SVC1202"; + prefix = "Accepted, Action not complete"; + response.setStatus(/*httpstatus=*/202); + break; + + case 403: + case ERR_Policy: + case ERR_Security: + case ERR_Denied: + msgId = "SVC1403"; + prefix = "Forbidden"; + response.setStatus(/*httpstatus=*/403); + break; + + case 404: + case ERR_NotFound: + msgId = "SVC1404"; + prefix = "Not Found"; + response.setStatus(/*httpstatus=*/404); + break; + + case 406: + case ERR_BadData: + msgId="SVC1406"; + prefix = "Not Acceptable"; + response.setStatus(/*httpstatus=*/406); + break; + + case 409: + case ERR_ConflictAlreadyExists: + msgId = "SVC1409"; + prefix = "Conflict Already Exists"; + response.setStatus(/*httpstatus=*/409); + break; + + case 501: + case ERR_NotImplemented: + msgId = "SVC1501"; + prefix = "Not Implemented"; + response.setStatus(/*httpstatus=*/501); + break; + + + default: + msgId = "SVC1500"; + prefix = "General Service Error"; + response.setStatus(/*httpstatus=*/500); + hidemsg=true; + break; + } + + try { + StringBuilder holder = new StringBuilder(); + ERROR em = mapper().errorFromMessage(holder, msgId,prefix + ": " + _msg,_detail); + trans.checkpoint( + "ErrResp [" + + msgId + + "] " + + holder.toString(), + Env.ALWAYS); + if(hidemsg) { + holder.setLength(0); + em = mapper().errorFromMessage(holder, msgId, "Server had an issue processing this request"); + } + errDF.newData(trans).load(em).to(response.getOutputStream()); + + } catch (Exception e) { + trans.error().log(e,"unable to send response for",_msg); + } + } + + @Override + public Result check(AuthzTrans trans, HttpServletResponse resp, String perm) throws IOException { + String[] p = Split.split('|',perm); + if(p.length!=3) { + return Result.err(Result.ERR_BadData,"Invalid Perm String"); + } + AAFPermission ap = new AAFPermission(p[0],p[1],p[2]); + if(certman.aafLurPerm.fish(trans.getUserPrincipal(), ap)) { + resp.setContentType(voidResp); + resp.getOutputStream().write(0); + return Result.ok(); + } else { + return Result.err(Result.ERR_Denied,"%s does not have %s",trans.user(),ap.getKey()); + } + } + + /* (non-Javadoc) + * @see com.att.auth.certman.facade.Facade#requestCert(org.onap.aaf.auth.env.test.AuthzTrans, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse) + */ + @Override + public Result requestCert(AuthzTrans trans, HttpServletRequest req, HttpServletResponse resp, CA ca) { + TimeTaken tt = trans.start(REQUEST_CERT, Env.SUB|Env.ALWAYS); + String wt; + boolean withTrust=(wt=req.getParameter("withTrust"))!=null || TRUE.equalsIgnoreCase(wt); + try { + REQ request; + try { + Data rd = certRequestDF.newData().load(req.getInputStream()); + request = rd.asObject(); + } catch(APIException e) { + trans.error().log("Invalid Input",IN,REQUEST_CERT); + return Result.err(Result.ERR_BadData,"Invalid Input"); + } + + Result rcr = service.requestCert(trans,mapper.toReq(trans,request), ca); + if(rcr.notOK()) { + return Result.err(rcr); + } + +// CA certAuth = trans.get(sCertAuth,null); + Result rc = mapper.toCert(trans, rcr, withTrust); + switch(rc.status) { + case OK: + RosettaData data = certDF.newData(trans).load(rc.value); + data.to(resp.getOutputStream()); + + setContentType(resp,certDF.getOutType()); + return Result.ok(); + default: + return Result.err(rc); + } + + } catch (Exception e) { + trans.error().log(e,IN,REQUEST_CERT); + return Result.err(e); + } finally { + tt.done(); + } + } + + /* (non-Javadoc) + * @see org.onap.aaf.auth.cm.facade.Facade#requestPersonalCert(org.onap.aaf.auth.env.test.AuthzTrans, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse, boolean) + */ + @Override + public Result requestPersonalCert(AuthzTrans trans, HttpServletRequest req, HttpServletResponse resp, CA ca) { + return Result.err(Result.ERR_NotImplemented,"not implemented yet"); +// Result rcr = service.requestPersonalCert(trans,ca); +// if(rcr.notOK()) { +// return Result.err(rcr); +// } else { +// try { +// resp.setContentType("application/zip, application/octet-stream"); +// ZipOutputStream zos = new ZipOutputStream(resp.getOutputStream()); +// PrintStream ps = new PrintStream(zos); +// ZipEntry ze = new ZipEntry(trans.user()+".key"); +// zos.putNextEntry(ze); +// ps.print(rcr.value.privateString()); +// zos.closeEntry(); +// +// zos.putNextEntry(new ZipEntry(trans.user()+".crt")); +// ps.print(rcr.value.asCertString()); +// zos.closeEntry(); +// +// String wt; +// if((wt=req.getParameter("withTrust"))!=null || TRUE.equalsIgnoreCase(wt)) { +// zos.putNextEntry(new ZipEntry(trans.user()+".trustCrts")); +// for(String s : ca.getTrustChain()) { +// ps.println(s); +// } +// zos.closeEntry(); +// } +// +// boolean withJKS = (wt=req.getParameter("withJKS"))!=null || TRUE.equalsIgnoreCase(wt); +// if(withJKS) { +// if(trans.getUserPrincipal() instanceof BasicPrincipal) { +// char[] cap = new String(((BasicPrincipal)trans.getUserPrincipal()).getCred()).toCharArray(); +// KeyStore ks = keystore(trans, rcr.value, ca.getTrustChain(), trans.user(), cap); +// zos.putNextEntry(new ZipEntry(trans.user()+".jks")); +// ks.store(zos, cap); +// zos.closeEntry(); +// } +// } +// +// zos.putNextEntry(new ZipEntry("cert_deploy.sh")); +// ps.println("# Deploy Certificate to ~/.aaf"); +// ps.println("if [ \"$1\" = \"\" ]; then echo \"sh deploy.sh \";exit; else chmod 700 $HOME/.aaf; fi"); +// ps.println("chmod 600 $1"); +// ps.println("if [ ! -e $HOME/.aaf ]; then mkdir -m 700 $HOME/.aaf; fi"); +// ps.println("THE_PWD=`pwd`"); +// ps.println("cd $HOME/.aaf"); +// ps.println("echo \"Deploying to `pwd`\""); +// ps.println("jar -xvf $THE_PWD/$1 " + trans.user()); +// ps.println("chmod 600 " + trans.user() + ".key"); +// if(withJKS) { +// ps.println("chmod 600 " + trans.user() + ".jks"); +// } +// ps.println("cd $THE_PWD"); +// ps.println("rm cert_deploy.sh"); +// zos.closeEntry(); +// +// +// zos.close(); +// +// } catch (IOException | KeyStoreException | CertificateException | APIException | CertException | NoSuchAlgorithmException e) { +// return Result.err(e); +// } +// } +// +// return Result.ok(); + } + + private KeyStore keystore(AuthzTrans trans, CertResp cr, String[] trustChain, String name, char[] cap) throws KeyStoreException, CertificateException, APIException, IOException, CertException, NoSuchAlgorithmException { + KeyStore jks = KeyStore.getInstance("jks"); + jks.load(null, cap); + + // Get the Cert(s)... Might include Trust store + List lcerts = new ArrayList(); + lcerts.add(cr.asCertString()); + for(String s : trustChain) { + lcerts.add(s); + } + + Collection certColl = Factory.toX509Certificate(lcerts); + X509Certificate[] certs = new X509Certificate[certColl.size()]; + certColl.toArray(certs); + KeyStore.ProtectionParameter protParam = new KeyStore.PasswordProtection(cap); + + PrivateKey pk = Factory.toPrivateKey(trans, cr.privateString()); + KeyStore.PrivateKeyEntry pkEntry = + new KeyStore.PrivateKeyEntry(pk, new Certificate[] {certs[0]}); + jks.setEntry(name, pkEntry, protParam); + + int i=0; + for(X509Certificate x509 : certs) { + jks.setCertificateEntry("cert_"+ ++i, x509); + } + return jks; + } + + @Override + public Result renewCert(AuthzTrans trans, HttpServletRequest req, HttpServletResponse resp, boolean withTrust) { + TimeTaken tt = trans.start(RENEW_CERT, Env.SUB|Env.ALWAYS); + try { + REQ request; + try { + Data rd = certRenewDF.newData().load(req.getInputStream()); + request = rd.asObject(); + } catch(APIException e) { + trans.error().log("Invalid Input",IN,RENEW_CERT); + return Result.err(Result.ERR_BadData,"Invalid Input"); + } + +// String certAuth = trans.get(sCertAuth,null); + Result rcr = service.renewCert(trans,mapper.toRenew(trans,request)); + Result rc = mapper.toCert(trans, rcr, withTrust); + + switch(rc.status) { + case OK: + RosettaData data = certDF.newData(trans).load(rc.value); + data.to(resp.getOutputStream()); + + setContentType(resp,certDF.getOutType()); + return Result.ok(); + default: + return Result.err(rc); + } + } catch (Exception e) { + trans.error().log(e,IN,RENEW_CERT); + return Result.err(e); + } finally { + tt.done(); + } + + } + + @Override + public Result dropCert(AuthzTrans trans, HttpServletRequest req, HttpServletResponse resp) { + TimeTaken tt = trans.start(DROP_CERT, Env.SUB|Env.ALWAYS); + try { + REQ request; + try { + Data rd = certDropDF.newData().load(req.getInputStream()); + request = rd.asObject(); + } catch(APIException e) { + trans.error().log("Invalid Input",IN,DROP_CERT); + return Result.err(Result.ERR_BadData,"Invalid Input"); + } + + Result rv = service.dropCert(trans,mapper.toDrop(trans, request)); + switch(rv.status) { + case OK: + setContentType(resp,certRequestDF.getOutType()); + return Result.ok(); + default: + return Result.err(rv); + } + } catch (Exception e) { + trans.error().log(e,IN,DROP_CERT); + return Result.err(e); + } finally { + tt.done(); + } + } + + /* (non-Javadoc) + * @see org.onap.aaf.auth.cm.facade.Facade#readCertsByMechID(org.onap.aaf.auth.env.test.AuthzTrans, javax.servlet.http.HttpServletResponse, java.lang.String) + */ + @Override + public Result readCertsByMechID(AuthzTrans trans, HttpServletResponse resp, String mechID) { + TimeTaken tt = trans.start(READ_CERTS_MECHID, Env.SUB|Env.ALWAYS); + try { + Result rc = mapper.toCert(trans, service.readCertsByMechID(trans,mechID)); + switch(rc.status) { + case OK: + RosettaData data = certDF.newData(trans).load(rc.value); + data.to(resp.getOutputStream()); + + setContentType(resp,certDF.getOutType()); + return Result.ok(); + default: + return Result.err(rc); + } + } catch (Exception e) { + trans.error().log(e,IN,READ_CERTS_MECHID); + return Result.err(e); + } finally { + tt.done(); + } + } + + //////////////////////////// + // Artifacts + //////////////////////////// + @Override + public Result createArtifacts(AuthzTrans trans, HttpServletRequest req, HttpServletResponse resp) { + TimeTaken tt = trans.start(CREATE_ARTIFACTS, Env.SUB); + try { + ARTIFACTS arti; + try { + Data rd = artiDF.newData().load(req.getInputStream()); + arti = rd.asObject(); + } catch(APIException e) { + trans.error().log("Invalid Input",IN,CREATE_ARTIFACTS); + return Result.err(Result.ERR_BadData,"Invalid Input"); + } + + return service.createArtifact(trans,mapper.toArtifact(trans,arti)); + } catch (Exception e) { + + trans.error().log(e,IN,CREATE_ARTIFACTS); + return Result.err(e); + } finally { + tt.done(); + } + } + + @Override + public Result readArtifacts(AuthzTrans trans, HttpServletRequest req, HttpServletResponse resp) { + TimeTaken tt = trans.start(READ_ARTIFACTS, Env.SUB); + try { + String mechid = req.getParameter("mechid"); + String machine = req.getParameter("machine"); + String ns = req.getParameter("ns"); + + Result ra; + if( machine !=null && mechid == null) { + ra = mapper.fromArtifacts(service.readArtifactsByMachine(trans, machine)); + } else if(mechid!=null && machine==null) { + ra = mapper.fromArtifacts(service.readArtifactsByMechID(trans, mechid)); + } else if(mechid!=null && machine!=null) { + ArtiDAO.Data add = new ArtiDAO.Data(); + add.mechid = mechid; + add.machine = machine; + add.ns = ns; + ra = mapper.fromArtifacts(service.readArtifacts(trans,add)); + } else if(ns!=null) { + ra = mapper.fromArtifacts(service.readArtifactsByNs(trans, ns)); + } else { + ra = Result.err(Status.ERR_BadData,"Invalid request inputs"); + } + + if(ra.isOK()) { + RosettaData data = artiDF.newData(trans).load(ra.value); + data.to(resp.getOutputStream()); + setContentType(resp,artiDF.getOutType()); + return Result.ok(); + } else { + return Result.err(ra); + } + + } catch (Exception e) { + trans.error().log(e,IN,READ_ARTIFACTS); + return Result.err(e); + } finally { + tt.done(); + } + } + + @Override + public Result readArtifacts(AuthzTrans trans, HttpServletResponse resp, String mechid, String machine) { + TimeTaken tt = trans.start(READ_ARTIFACTS, Env.SUB); + try { + ArtiDAO.Data add = new ArtiDAO.Data(); + add.mechid = mechid; + add.machine = machine; + Result ra = mapper.fromArtifacts(service.readArtifacts(trans,add)); + if(ra.isOK()) { + RosettaData data = artiDF.newData(trans).load(ra.value); + data.to(resp.getOutputStream()); + setContentType(resp,artiDF.getOutType()); + return Result.ok(); + } else { + return Result.err(ra); + } + } catch (Exception e) { + trans.error().log(e,IN,READ_ARTIFACTS); + return Result.err(e); + } finally { + tt.done(); + } + } + + + @Override + public Result updateArtifacts(AuthzTrans trans, HttpServletRequest req, HttpServletResponse resp) { + TimeTaken tt = trans.start(UPDATE_ARTIFACTS, Env.SUB); + try { + ARTIFACTS arti; + try { + Data rd = artiDF.newData().load(req.getInputStream()); + arti = rd.asObject(); + } catch(APIException e) { + trans.error().log("Invalid Input",IN,UPDATE_ARTIFACTS); + return Result.err(Result.ERR_BadData,"Invalid Input"); + } + + return service.updateArtifact(trans,mapper.toArtifact(trans,arti)); + } catch (Exception e) { + trans.error().log(e,IN,UPDATE_ARTIFACTS); + return Result.err(e); + } finally { + tt.done(); + } + } + + @Override + public Result deleteArtifacts(AuthzTrans trans, HttpServletRequest req, HttpServletResponse resp) { + TimeTaken tt = trans.start(DELETE_ARTIFACTS, Env.SUB); + try { + ARTIFACTS arti; + try { + Data rd = artiDF.newData().load(req.getInputStream()); + arti = rd.asObject(); + } catch(APIException e) { + trans.error().log("Invalid Input",IN,DELETE_ARTIFACTS); + return Result.err(Result.ERR_BadData,"Invalid Input"); + } + + Result rv = service.deleteArtifact(trans,mapper.toArtifact(trans,arti)); + switch(rv.status) { + case OK: + setContentType(resp,artiDF.getOutType()); + } + return rv; + } catch (Exception e) { + trans.error().log(e,IN,DELETE_ARTIFACTS); + return Result.err(e); + } finally { + tt.done(); + } + } + + @Override + public Result deleteArtifacts(AuthzTrans trans, HttpServletResponse resp, String mechid, String machine) { + TimeTaken tt = trans.start(DELETE_ARTIFACTS, Env.SUB); + try { + Result rv = service.deleteArtifact(trans, mechid, machine); + switch(rv.status) { + case OK: + setContentType(resp,artiDF.getOutType()); + } + return rv; + } catch (Exception e) { + trans.error().log(e,IN,DELETE_ARTIFACTS); + return Result.err(e); + } finally { + tt.done(); + } + } + + +} \ No newline at end of file diff --git a/auth/auth-certman/src/main/java/org/onap/aaf/auth/cm/mapper/Mapper.java b/auth/auth-certman/src/main/java/org/onap/aaf/auth/cm/mapper/Mapper.java new file mode 100644 index 00000000..aadb6650 --- /dev/null +++ b/auth/auth-certman/src/main/java/org/onap/aaf/auth/cm/mapper/Mapper.java @@ -0,0 +1,54 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.cm.mapper; + +import java.io.IOException; +import java.util.List; + +import org.onap.aaf.auth.cm.data.CertDrop; +import org.onap.aaf.auth.cm.data.CertRenew; +import org.onap.aaf.auth.cm.data.CertReq; +import org.onap.aaf.auth.cm.data.CertResp; +import org.onap.aaf.auth.dao.cass.ArtiDAO; +import org.onap.aaf.auth.dao.cass.CertDAO; +import org.onap.aaf.auth.env.AuthzTrans; +import org.onap.aaf.auth.layer.Result; + +public interface Mapper +{ + public enum API{ERROR,VOID,CERT,CERT_REQ,CERT_RENEW,CERT_DROP,ARTIFACTS}; + + public Class getClass(API api); + public A newInstance(API api); + + public ERROR errorFromMessage(StringBuilder holder, String msgID, String text, String... detail); + + public Result toCert(AuthzTrans trans, Result in, boolean withTrustChain) throws IOException; + public Result toCert(AuthzTrans trans, Result> in); + + public Result toReq(AuthzTrans trans, REQ req); + public Result toRenew(AuthzTrans trans, REQ req); + public Result toDrop(AuthzTrans trans, REQ req); + + public List toArtifact(AuthzTrans trans, ARTIFACTS arti); + public Result fromArtifacts(Result> readArtifactsByMachine); +} diff --git a/auth/auth-certman/src/main/java/org/onap/aaf/auth/cm/mapper/Mapper1_0.java b/auth/auth-certman/src/main/java/org/onap/aaf/auth/cm/mapper/Mapper1_0.java new file mode 100644 index 00000000..3d865d30 --- /dev/null +++ b/auth/auth-certman/src/main/java/org/onap/aaf/auth/cm/mapper/Mapper1_0.java @@ -0,0 +1,274 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.cm.mapper; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +import org.onap.aaf.auth.cm.data.CertDrop; +import org.onap.aaf.auth.cm.data.CertRenew; +import org.onap.aaf.auth.cm.data.CertReq; +import org.onap.aaf.auth.cm.data.CertResp; +import org.onap.aaf.auth.cm.validation.CertmanValidator; +import org.onap.aaf.auth.dao.cass.ArtiDAO; +import org.onap.aaf.auth.dao.cass.CertDAO; +import org.onap.aaf.auth.dao.cass.ArtiDAO.Data; +import org.onap.aaf.auth.env.AuthzTrans; +import org.onap.aaf.auth.layer.Result; +import org.onap.aaf.cadi.util.FQI; +import org.onap.aaf.cadi.util.Vars; + +import aaf.v2_0.Error; +import certman.v1_0.Artifacts; +import certman.v1_0.Artifacts.Artifact; +import certman.v1_0.BaseRequest; +import certman.v1_0.CertInfo; +import certman.v1_0.CertificateDrop; +import certman.v1_0.CertificateRenew; +import certman.v1_0.CertificateRequest; + + +public class Mapper1_0 implements Mapper { + + @Override + public Class getClass(API api) { + switch(api) { + case CERT_REQ: return CertificateRequest.class; + case CERT_RENEW: return CertificateRenew.class; + case CERT_DROP: return CertificateDrop.class; + case CERT: return CertInfo.class; + case ARTIFACTS: return Artifacts.class; + case ERROR: return Error.class; + case VOID: return Void.class; + } + return null; + } + + @SuppressWarnings("unchecked") + @Override + public A newInstance(API api) { + switch(api) { + case CERT_REQ: return (A) new CertificateRequest(); + case CERT_RENEW: return (A) new CertificateRenew(); + case CERT_DROP: return (A) new CertificateDrop(); + case CERT: return (A) new CertInfo(); + case ARTIFACTS: return (A) new Artifacts(); + case ERROR: return (A)new Error(); + case VOID: return null; + } + return null; + } + + ////////////// Mapping Functions ///////////// + @Override + public Error errorFromMessage(StringBuilder holder, String msgID, String text, String... var) { + Error err = new Error(); + err.setMessageId(msgID); + // AT&T Restful Error Format requires numbers "%" placements + err.setText(Vars.convert(holder, text, var)); + for(String s : var) { + err.getVariables().add(s); + } + return err; + } + + /* (non-Javadoc) + * @see com.att.authz.certman.mapper.Mapper#toCert(org.onap.aaf.auth.env.test.AuthzTrans, org.onap.aaf.auth.layer.test.Result) + */ + @Override + public Result toCert(AuthzTrans trans, Result in, boolean withTrustChain) throws IOException { + if(in.isOK()) { + CertResp cin = in.value; + CertInfo cout = newInstance(API.CERT); + cout.setPrivatekey(cin.privateString()); + String value; + if((value=cin.challenge())!=null) { + cout.setChallenge(value); + } + cout.getCerts().add(cin.asCertString()); + if(cin.trustChain()!=null) { + for(String c : cin.trustChain()) { + if(c!=null) { + cout.getCerts().add(c); + } + } + } + // Adding all the Certs in one response is a mistake. Makes it very hard for Agent to setup + // Certs in keystore versus Truststore. Separate in Version 2_0 + if(cin.trustCAs()!=null) { + for(String c : cin.trustCAs()) { + if(c!=null) { + cout.getCerts().add(c); + } + } + } + if(cin.notes()!=null) { + boolean first = true; + StringBuilder sb = new StringBuilder(); + for(String n : cin.notes()) { + if(first) { + first = false; + } else { + sb.append('\n'); + } + sb.append(n); + } + cout.setNotes(sb.toString()); + } + cout.getCaIssuerDNs().addAll(cin.caIssuerDNs()); + cout.setEnv(cin.env()); + return Result.ok(cout); + } else { + return Result.err(in); + } + } + + @Override + public Result toCert(AuthzTrans trans, Result> in) { + if(in.isOK()) { + CertInfo cout = newInstance(API.CERT); + List certs = cout.getCerts(); + for(CertDAO.Data cdd : in.value) { + certs.add(cdd.x509); + } + return Result.ok(cout); + } else { + return Result.err(in); + } + } + + /* (non-Javadoc) + * @see com.att.authz.certman.mapper.Mapper#toReq(org.onap.aaf.auth.env.test.AuthzTrans, java.lang.Object) + */ + @Override + public Result toReq(AuthzTrans trans, BaseRequest req) { + CertificateRequest in; + try { + in = (CertificateRequest)req; + } catch(ClassCastException e) { + return Result.err(Result.ERR_BadData,"Request is not a CertificateRequest"); + } + + CertReq out = new CertReq(); + CertmanValidator v = new CertmanValidator(); + v.isNull("CertRequest", req) + .nullOrBlank("MechID", out.mechid=in.getMechid()); + v.nullBlankMin("FQDNs", out.fqdns=in.getFqdns(),1); + if(v.err()) { + return Result.err(Result.ERR_BadData, v.errs()); + } + out.emails = in.getEmail(); + out.sponsor=in.getSponsor(); + out.start = in.getStart(); + out.end = in.getEnd(); + out.fqdns = in.getFqdns(); + return Result.ok(out); + } + + /* (non-Javadoc) + * @see com.att.authz.certman.mapper.Mapper#toRenew(org.onap.aaf.auth.env.test.AuthzTrans, java.lang.Object) + */ + @Override + public Result toRenew(AuthzTrans trans, BaseRequest req) { + return Result.err(Result.ERR_NotImplemented,"Not Implemented... yet"); + } + + /* (non-Javadoc) + * @see com.att.authz.certman.mapper.Mapper#toDrop(org.onap.aaf.auth.env.test.AuthzTrans, java.lang.Object) + */ + @Override + public Result toDrop(AuthzTrans trans, BaseRequest req) { + return Result.err(Result.ERR_NotImplemented,"Not Implemented... yet"); + } + + /* (non-Javadoc) + * @see org.onap.aaf.auth.cm.mapper.Mapper#toArtifact(org.onap.aaf.auth.env.test.AuthzTrans, java.lang.Object) + */ + @Override + public List toArtifact(AuthzTrans trans, Artifacts artifacts) { + List ladd = new ArrayList(); + for(Artifact arti : artifacts.getArtifact()) { + ArtiDAO.Data data = new ArtiDAO.Data(); + data.mechid = arti.getMechid(); + data.machine = arti.getMachine(); + data.type(true).addAll(arti.getType()); + data.ca = arti.getCa(); + data.dir = arti.getDir(); + data.os_user = arti.getOsUser(); + // Optional (on way in) + data.ns = arti.getNs(); + data.renewDays = arti.getRenewDays(); + data.notify = arti.getNotification(); + + // Ignored on way in for create/update + data.sponsor = arti.getSponsor(); + data.expires = null; + + // Derive Optional Data from Machine (Domain) if exists + if(data.machine!=null) { + if(data.ca==null) { + if(data.machine.endsWith(".att.com")) { + data.ca = "aaf"; // default + } + } + if(data.ns==null ) { + data.ns=FQI.reverseDomain(data.machine); + } + } + data.sans(true).addAll(arti.getSans()); + ladd.add(data); + } + return ladd; + } + + /* (non-Javadoc) + * @see org.onap.aaf.auth.cm.mapper.Mapper#fromArtifacts(org.onap.aaf.auth.layer.test.Result) + */ + @Override + public Result fromArtifacts(Result> lArtiDAO) { + if(lArtiDAO.isOK()) { + Artifacts artis = new Artifacts(); + for(ArtiDAO.Data arti : lArtiDAO.value) { + Artifact a = new Artifact(); + a.setMechid(arti.mechid); + a.setMachine(arti.machine); + a.setSponsor(arti.sponsor); + a.setNs(arti.ns); + a.setCa(arti.ca); + a.setDir(arti.dir); + a.getType().addAll(arti.type(false)); + a.setOsUser(arti.os_user); + a.setRenewDays(arti.renewDays); + a.setNotification(arti.notify); + a.getSans().addAll(arti.sans(false)); + artis.getArtifact().add(a); + } + return Result.ok(artis); + } else { + return Result.err(lArtiDAO); + } + } + + + +} \ No newline at end of file diff --git a/auth/auth-certman/src/main/java/org/onap/aaf/auth/cm/mapper/Mapper2_0.java b/auth/auth-certman/src/main/java/org/onap/aaf/auth/cm/mapper/Mapper2_0.java new file mode 100644 index 00000000..13123bdf --- /dev/null +++ b/auth/auth-certman/src/main/java/org/onap/aaf/auth/cm/mapper/Mapper2_0.java @@ -0,0 +1,268 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.cm.mapper; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +import org.onap.aaf.auth.cm.data.CertDrop; +import org.onap.aaf.auth.cm.data.CertRenew; +import org.onap.aaf.auth.cm.data.CertReq; +import org.onap.aaf.auth.cm.data.CertResp; +import org.onap.aaf.auth.cm.validation.CertmanValidator; +import org.onap.aaf.auth.dao.cass.ArtiDAO; +import org.onap.aaf.auth.dao.cass.ArtiDAO.Data; +import org.onap.aaf.auth.dao.cass.CertDAO; +import org.onap.aaf.auth.env.AuthzTrans; +import org.onap.aaf.auth.layer.Result; +import org.onap.aaf.cadi.util.FQI; +import org.onap.aaf.cadi.util.Vars; + +import aaf.v2_0.Error; +import certman.v1_0.Artifacts; +import certman.v1_0.Artifacts.Artifact; +import certman.v1_0.BaseRequest; +import certman.v1_0.CertInfo; +import certman.v1_0.CertificateDrop; +import certman.v1_0.CertificateRenew; +import certman.v1_0.CertificateRequest; + + +public class Mapper2_0 implements Mapper { + + @Override + public Class getClass(API api) { + switch(api) { + case CERT_REQ: return CertificateRequest.class; + case CERT_RENEW: return CertificateRenew.class; + case CERT_DROP: return CertificateDrop.class; + case CERT: return CertInfo.class; + case ARTIFACTS: return Artifacts.class; + case ERROR: return Error.class; + case VOID: return Void.class; + } + return null; + } + + @SuppressWarnings("unchecked") + @Override + public A newInstance(API api) { + switch(api) { + case CERT_REQ: return (A) new CertificateRequest(); + case CERT_RENEW: return (A) new CertificateRenew(); + case CERT_DROP: return (A) new CertificateDrop(); + case CERT: return (A) new CertInfo(); + case ARTIFACTS: return (A) new Artifacts(); + case ERROR: return (A)new Error(); + case VOID: return null; + } + return null; + } + + ////////////// Mapping Functions ///////////// + @Override + public Error errorFromMessage(StringBuilder holder, String msgID, String text, String... var) { + Error err = new Error(); + err.setMessageId(msgID); + // AT&T Restful Error Format requires numbers "%" placements + err.setText(Vars.convert(holder, text, var)); + for(String s : var) { + err.getVariables().add(s); + } + return err; + } + + /* (non-Javadoc) + * @see com.att.authz.certman.mapper.Mapper#toCert(org.onap.aaf.auth.env.test.AuthzTrans, org.onap.aaf.auth.layer.test.Result) + */ + /* (non-Javadoc) + * @see com.att.authz.certman.mapper.Mapper#toCert(org.onap.aaf.auth.env.test.AuthzTrans, org.onap.aaf.auth.layer.test.Result) + */ + @Override + public Result toCert(AuthzTrans trans, Result in, boolean withTrustChain) throws IOException { + if(in.isOK()) { + CertResp cin = in.value; + CertInfo cout = newInstance(API.CERT); + cout.setPrivatekey(cin.privateString()); + String value; + if((value=cin.challenge())!=null) { + cout.setChallenge(value); + } + cout.getCerts().add(cin.asCertString()); + if(cin.trustChain()!=null) { + for(String c : cin.trustChain()) { + cout.getCerts().add(c); + } + } + if(cin.notes()!=null) { + boolean first = true; + StringBuilder sb = new StringBuilder(); + for(String n : cin.notes()) { + if(first) { + first = false; + } else { + sb.append('\n'); + } + sb.append(n); + } + cout.setNotes(sb.toString()); + } + cout.getCaIssuerDNs().addAll(cin.caIssuerDNs()); + cout.setEnv(cin.env()); + return Result.ok(cout); + } else { + return Result.err(in); + } + } + + + @Override + public Result toCert(AuthzTrans trans, Result> in) { + if(in.isOK()) { + CertInfo cout = newInstance(API.CERT); + List certs = cout.getCerts(); + for(CertDAO.Data cdd : in.value) { + certs.add(cdd.x509); + } + return Result.ok(cout); + } else { + return Result.err(in); + } + } + + /* (non-Javadoc) + * @see com.att.authz.certman.mapper.Mapper#toReq(org.onap.aaf.auth.env.test.AuthzTrans, java.lang.Object) + */ + @Override + public Result toReq(AuthzTrans trans, BaseRequest req) { + CertificateRequest in; + try { + in = (CertificateRequest)req; + } catch(ClassCastException e) { + return Result.err(Result.ERR_BadData,"Request is not a CertificateRequest"); + } + + CertReq out = new CertReq(); + CertmanValidator v = new CertmanValidator(); + v.isNull("CertRequest", req) + .nullOrBlank("MechID", out.mechid=in.getMechid()); + v.nullBlankMin("FQDNs", out.fqdns=in.getFqdns(),1); + if(v.err()) { + return Result.err(Result.ERR_BadData, v.errs()); + } + + out.emails = in.getEmail(); + out.sponsor=in.getSponsor(); + out.start = in.getStart(); + out.end = in.getEnd(); + out.fqdns = in.getFqdns(); + return Result.ok(out); + } + + /* (non-Javadoc) + * @see com.att.authz.certman.mapper.Mapper#toRenew(org.onap.aaf.auth.env.test.AuthzTrans, java.lang.Object) + */ + @Override + public Result toRenew(AuthzTrans trans, BaseRequest req) { + return Result.err(Result.ERR_NotImplemented,"Not Implemented... yet"); + } + + /* (non-Javadoc) + * @see com.att.authz.certman.mapper.Mapper#toDrop(org.onap.aaf.auth.env.test.AuthzTrans, java.lang.Object) + */ + @Override + public Result toDrop(AuthzTrans trans, BaseRequest req) { + return Result.err(Result.ERR_NotImplemented,"Not Implemented... yet"); + } + + /* (non-Javadoc) + * @see org.onap.aaf.auth.cm.mapper.Mapper#toArtifact(org.onap.aaf.auth.env.test.AuthzTrans, java.lang.Object) + */ + @Override + public List toArtifact(AuthzTrans trans, Artifacts artifacts) { + List ladd = new ArrayList(); + for(Artifact arti : artifacts.getArtifact()) { + ArtiDAO.Data data = new ArtiDAO.Data(); + data.mechid = arti.getMechid(); + data.machine = arti.getMachine(); + data.type(true).addAll(arti.getType()); + data.ca = arti.getCa(); + data.dir = arti.getDir(); + data.os_user = arti.getOsUser(); + // Optional (on way in) + data.ns = arti.getNs(); + data.renewDays = arti.getRenewDays(); + data.notify = arti.getNotification(); + + // Ignored on way in for create/update + data.sponsor = arti.getSponsor(); + data.expires = null; + + // Derive Optional Data from Machine (Domain) if exists + if(data.machine!=null) { + if(data.ca==null) { + if(data.machine.endsWith(".att.com")) { + data.ca = "aaf"; // default + } + } + if(data.ns==null ) { + data.ns=FQI.reverseDomain(data.machine); + } + } + data.sans(true).addAll(arti.getSans()); + ladd.add(data); + } + return ladd; + } + + /* (non-Javadoc) + * @see org.onap.aaf.auth.cm.mapper.Mapper#fromArtifacts(org.onap.aaf.auth.layer.test.Result) + */ + @Override + public Result fromArtifacts(Result> lArtiDAO) { + if(lArtiDAO.isOK()) { + Artifacts artis = new Artifacts(); + for(ArtiDAO.Data arti : lArtiDAO.value) { + Artifact a = new Artifact(); + a.setMechid(arti.mechid); + a.setMachine(arti.machine); + a.setSponsor(arti.sponsor); + a.setNs(arti.ns); + a.setCa(arti.ca); + a.setDir(arti.dir); + a.getType().addAll(arti.type(false)); + a.setOsUser(arti.os_user); + a.setRenewDays(arti.renewDays); + a.setNotification(arti.notify); + a.getSans().addAll(arti.sans(false)); + artis.getArtifact().add(a); + } + return Result.ok(artis); + } else { + return Result.err(lArtiDAO); + } + } + + + +} \ No newline at end of file diff --git a/auth/auth-certman/src/main/java/org/onap/aaf/auth/cm/service/CMService.java b/auth/auth-certman/src/main/java/org/onap/aaf/auth/cm/service/CMService.java new file mode 100644 index 00000000..f6407d90 --- /dev/null +++ b/auth/auth-certman/src/main/java/org/onap/aaf/auth/cm/service/CMService.java @@ -0,0 +1,693 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.cm.service; + +import java.io.IOException; +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.nio.ByteBuffer; +import java.security.NoSuchAlgorithmException; +import java.security.cert.X509Certificate; +import java.util.ArrayList; +import java.util.Date; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import org.onap.aaf.auth.cm.AAF_CM; +import org.onap.aaf.auth.cm.ca.CA; +import org.onap.aaf.auth.cm.ca.X509andChain; +import org.onap.aaf.auth.cm.cert.BCFactory; +import org.onap.aaf.auth.cm.cert.CSRMeta; +import org.onap.aaf.auth.cm.data.CertDrop; +import org.onap.aaf.auth.cm.data.CertRenew; +import org.onap.aaf.auth.cm.data.CertReq; +import org.onap.aaf.auth.cm.data.CertResp; +import org.onap.aaf.auth.cm.validation.CertmanValidator; +import org.onap.aaf.auth.dao.CassAccess; +import org.onap.aaf.auth.dao.cass.ArtiDAO; +import org.onap.aaf.auth.dao.cass.CacheInfoDAO; +import org.onap.aaf.auth.dao.cass.CertDAO; +import org.onap.aaf.auth.dao.cass.CertDAO.Data; +import org.onap.aaf.auth.dao.cass.CredDAO; +import org.onap.aaf.auth.dao.cass.HistoryDAO; +import org.onap.aaf.auth.dao.cass.Status; +import org.onap.aaf.auth.dao.hl.Question; +import org.onap.aaf.auth.env.AuthzTrans; +import org.onap.aaf.auth.layer.Result; +import org.onap.aaf.auth.org.Organization; +import org.onap.aaf.auth.org.Organization.Identity; +import org.onap.aaf.auth.org.OrganizationException; +import org.onap.aaf.cadi.Hash; +import org.onap.aaf.cadi.aaf.AAFPermission; +import org.onap.aaf.cadi.cm.Factory; +import org.onap.aaf.cadi.util.FQI; +import org.onap.aaf.misc.env.APIException; +import org.onap.aaf.misc.env.util.Chrono; + + +public class CMService { + // If we add more CAs, may want to parameterize + private static final int STD_RENEWAL = 30; + private static final int MAX_RENEWAL = 60; + private static final int MIN_RENEWAL = 10; + + public static final String REQUEST = "request"; + public static final String RENEW = "renew"; + public static final String DROP = "drop"; +// public static final String SANS = "san"; + public static final String IPS = "ips"; + public static final String DOMAIN = "domain"; + + private static final String[] NO_NOTES = new String[0]; + private final CertDAO certDAO; + private final CredDAO credDAO; + private final ArtiDAO artiDAO; +// private DAO[] daos; + private AAF_CM certman; + +// @SuppressWarnings("unchecked") + public CMService(final AuthzTrans trans, AAF_CM certman) throws APIException, IOException { + // Jonathan 4/2015 SessionFilter unneeded... DataStax already deals with Multithreading well + + HistoryDAO hd = new HistoryDAO(trans, certman.cluster, CassAccess.KEYSPACE); + CacheInfoDAO cid = new CacheInfoDAO(trans, hd); + certDAO = new CertDAO(trans, hd, cid); + credDAO = new CredDAO(trans, hd, cid); + artiDAO = new ArtiDAO(trans, hd, cid); + +// daos =(DAO[]) new DAO[] { +// hd,cid,certDAO,credDAO,artiDAO +// }; +// + this.certman = certman; + } + + public Result requestCert(final AuthzTrans trans,final Result req, final CA ca) { + if(req.isOK()) { + + if(req.value.fqdns.isEmpty()) { + return Result.err(Result.ERR_BadData,"No Machines passed in Request"); + } + + String key = req.value.fqdns.get(0); + + // Policy 6: Requester must be granted Change permission in Namespace requested + String mechNS = FQI.reverseDomain(req.value.mechid); + if(mechNS==null) { + return Result.err(Status.ERR_Denied, "%s does not reflect a valid AAF Namespace",req.value.mechid); + } + + + // Disallow non-AAF CA without special permission + if(!ca.getName().equals("aaf") && !trans.fish( new AAFPermission(mechNS+".certman", ca.getName(), REQUEST))) { + return Result.err(Status.ERR_Denied, "'%s' does not have permission to request Certificates from Certificate Authority '%s'", + trans.user(),ca.getName()); + } + + List notes = null; + List fqdns = new ArrayList(req.value.fqdns); + + + String email = null; + + try { + Organization org = trans.org(); + + InetAddress primary = null; + // Organize incoming information to get to appropriate Artifact + if(fqdns.size()>=1) { + // Accept domain wild cards, but turn into real machines + // Need *domain.com:real.machine.domain.com:san.machine.domain.com:... + if(fqdns.get(0).startsWith("*")) { // Domain set + if(!trans.fish(new AAFPermission(ca.getPermType(), ca.getName(), DOMAIN))) { + return Result.err(Result.ERR_Denied, "Domain based Authorizations (" + fqdns.get(0) + ") requires Exception"); + } + + //TODO check for Permission in Add Artifact? + String domain = fqdns.get(0).substring(1); + fqdns.remove(0); + if(fqdns.size()>=1) { + InetAddress ia = InetAddress.getByName(fqdns.get(0)); + if(ia==null) { + return Result.err(Result.ERR_Denied, "Request not made from matching IP matching domain"); + } else if(ia.getHostName().endsWith(domain)) { + primary = ia; + } + } else { + return Result.err(Result.ERR_Denied, "Requests using domain require machine declaration"); + } + + } else { + for(String cn : req.value.fqdns) { + try { + InetAddress[] ias = InetAddress.getAllByName(cn); + Set potentialSanNames = new HashSet(); + for(InetAddress ia1 : ias) { + InetAddress ia2 = InetAddress.getByAddress(ia1.getAddress()); + if(primary==null && ias.length==1 && trans.ip().equals(ia1.getHostAddress())) { + primary = ia1; + } else if(!cn.equals(ia1.getHostName()) && !ia2.getHostName().equals(ia2.getHostAddress())) { + potentialSanNames.add(ia1.getHostName()); + } + } + } catch (UnknownHostException e1) { + return Result.err(Result.ERR_BadData,"There is no DNS lookup for %s",cn); + } + + } + } + } + + if(primary==null) { + return Result.err(Result.ERR_Denied, "Request not made from matching IP (%s)",trans.ip()); +// return Result.err(Result.ERR_BadData,"Calling Machine does not match DNS lookup for %s",req.value.fqdns.get(0)); + } + + ArtiDAO.Data add = null; + Result> ra = artiDAO.read(trans, req.value.mechid,primary.getHostAddress()); + if(ra.isOKhasData()) { + if(add==null) { + add = ra.value.get(0); // single key + } + } else { + ra = artiDAO.read(trans, req.value.mechid,key); + if(ra.isOKhasData()) { // is the Template available? + add = ra.value.get(0); + add.machine=primary.getHostName(); + for(String s : fqdns) { + if(!s.equals(add.machine)) { + add.sans(true).add(s); + } + } + Result rc = artiDAO.create(trans, add); // Create new Artifact from Template + if(rc.notOK()) { + return Result.err(rc); + } + } else { + add = ra.value.get(0); + } + } + + // Add Artifact listed FQDNs + if(add.sans!=null) { + for(String s : add.sans) { + if(!fqdns.contains(s)) { + fqdns.add(s); + } + } + } + + // Policy 2: If Config marked as Expired, do not create or renew + Date now = new Date(); + if(add.expires!=null && now.after(add.expires)) { + return Result.err(Result.ERR_Policy,"Configuration for %s %s is expired %s",add.mechid,add.machine,Chrono.dateFmt.format(add.expires)); + } + + // Policy 3: MechID must be current + Identity muser = org.getIdentity(trans, add.mechid); + if(muser == null) { + return Result.err(Result.ERR_Policy,"MechID must exist in %s",org.getName()); + } + + // Policy 4: Sponsor must be current + Identity ouser = muser.responsibleTo(); + if(ouser==null) { + return Result.err(Result.ERR_Policy,"%s does not have a current sponsor at %s",add.mechid,org.getName()); + } else if(!ouser.isFound() || ouser.mayOwn()!=null) { + return Result.err(Result.ERR_Policy,"%s reports that %s cannot be responsible for %s",org.getName(),trans.user()); + } + + // Set Email from most current Sponsor + email = ouser.email(); + + // Policy 5: keep Artifact data current + if(!ouser.fullID().equals(add.sponsor)) { + add.sponsor = ouser.fullID(); + artiDAO.update(trans, add); + } + + // Policy 7: Caller must be the MechID or have specifically delegated permissions + if(!(trans.user().equals(req.value.mechid) || trans.fish(new AAFPermission(mechNS + ".certman", ca.getName() , "request")))) { + return Result.err(Status.ERR_Denied, "%s must have access to modify x509 certs in NS %s",trans.user(),mechNS); + } + + // Policy 8: SANs only allowed by Exception... need permission + // 7/25/2017 - SAN Permission no longer required. CSO +// if(fqdns.size()>1 && !certman.aafLurPerm.fish( +// new Principal() { +// @Override +// public String getName() { +// return req.value.mechid; +// } +// }, +// new AAFPermission(ca.getPermType(), ca.getName(), SANS))) { +// if(notes==null) {notes = new ArrayList();} +// notes.add("Warning: Subject Alternative Names only allowed by Permission: Get CSO Exception."); +// return Result.err(Status.ERR_Denied, "%s must have a CSO Exception to work with SAN",trans.user()); +// } + + // Make sure Primary is the first in fqdns + if(fqdns.size()>1) { + for(int i=0;i renewCert(AuthzTrans trans, Result renew) { + if(renew.isOK()) { + return Result.err(Result.ERR_NotImplemented,"Not implemented yet"); + } else { + return Result.err(renew); + } + } + + public Result dropCert(AuthzTrans trans, Result drop) { + if(drop.isOK()) { + return Result.err(Result.ERR_NotImplemented,"Not implemented yet"); + } else { + return Result.err(drop); + } + } + + public Result> readCertsByMechID(AuthzTrans trans, String mechID) { + // Policy 1: To Read, must have NS Read or is Sponsor + String ns = Question.domain2ns(mechID); + try { + if( trans.user().equals(mechID) + || trans.fish(new AAFPermission(ns + ".access", "*", "read")) + || (trans.org().validate(trans,Organization.Policy.OWNS_MECHID,null,mechID))==null) { + return certDAO.readID(trans, mechID); + } else { + return Result.err(Result.ERR_Denied,"%s is not the ID, Sponsor or NS Owner/Admin for %s at %s", + trans.user(),mechID,trans.org().getName()); + } + } catch(OrganizationException e) { + return Result.err(e); + } + } + + public Result requestPersonalCert(AuthzTrans trans, CA ca) { + if(ca.inPersonalDomains(trans.getUserPrincipal())) { + Organization org = trans.org(); + + // Policy 1: MechID must be current + Identity ouser; + try { + ouser = org.getIdentity(trans, trans.user()); + } catch (OrganizationException e1) { + trans.error().log(e1); + ouser = null; + } + if(ouser == null) { + return Result.err(Result.ERR_Policy,"Requesting User must exist in %s",org.getName()); + } + + // Set Email from most current Sponsor + + CSRMeta csrMeta; + try { + csrMeta = BCFactory.createPersonalCSRMeta( + ca, + trans.user(), + ouser.email()); + X509andChain x509ac = ca.sign(trans, csrMeta); + if(x509ac==null) { + return Result.err(Result.ERR_ActionNotCompleted,"x509 Certificate not signed by CA"); + } + X509Certificate x509 = x509ac.getX509(); + CertDAO.Data cdd = new CertDAO.Data(); + cdd.ca=ca.getName(); + cdd.serial=x509.getSerialNumber(); + cdd.id=trans.user(); + cdd.x500=x509.getSubjectDN().getName(); + cdd.x509=Factory.toString(trans, x509); + certDAO.create(trans, cdd); + + CertResp cr = new CertResp(trans, ca, x509, csrMeta, x509ac.getTrustChain(), ca.getTrustedCAs(), compileNotes(null)); + return Result.ok(cr); + } catch (Exception e) { + trans.error().log(e); + return Result.err(Result.ERR_ActionNotCompleted,e.getMessage()); + } + } else { + return Result.err(Result.ERR_Denied,trans.user()," not supported for CA",ca.getName()); + } + } + + /////////////// + // Artifact + ////////////// + public Result createArtifact(AuthzTrans trans, List list) { + CertmanValidator v = new CertmanValidator().artisRequired(list, 1); + if(v.err()) { + return Result.err(Result.ERR_BadData,v.errs()); + } + for(ArtiDAO.Data add : list) { + try { + // Policy 1: MechID must exist in Org + Identity muser = trans.org().getIdentity(trans, add.mechid); + if(muser == null) { + return Result.err(Result.ERR_Denied,"%s is not valid for %s", add.mechid,trans.org().getName()); + } + + // Policy 2: MechID must have valid Organization Owner + Identity ouser = muser.responsibleTo(); + if(ouser == null) { + return Result.err(Result.ERR_Denied,"%s is not a valid Sponsor for %s at %s", + trans.user(),add.mechid,trans.org().getName()); + } + + // Policy 3: Calling ID must be MechID Owner + if(!trans.user().equals(ouser.fullID())) { + return Result.err(Result.ERR_Denied,"%s is not the Sponsor for %s at %s", + trans.user(),add.mechid,trans.org().getName()); + } + + // Policy 4: Renewal Days are between 10 and 60 (constants, may be parameterized) + if(add.renewDaysMAX_RENEWAL) { + add.renewDays = MAX_RENEWAL; + } + + // Policy 5: If Notify is blank, set to Owner's Email + if(add.notify==null || add.notify.length()==0) { + add.notify = "mailto:"+ouser.email(); + } + + // Policy 6: Only do Domain by Exception + if(add.machine.startsWith("*")) { // Domain set + CA ca = certman.getCA(add.ca); + + + if(!trans.fish(new AAFPermission(ca.getPermType(), add.ca, DOMAIN))) { + return Result.err(Result.ERR_Denied,"Domain Artifacts (%s) requires specific Permission", + add.machine); + } + } + + // Set Sponsor from Golden Source + add.sponsor = ouser.fullID(); + + + } catch (OrganizationException e) { + return Result.err(e); + } + // Add to DB + Result rv = artiDAO.create(trans, add); + // TODO come up with Partial Reporting Scheme, or allow only one at a time. + if(rv.notOK()) { + return Result.err(rv); + } + } + return Result.ok(); + } + + public Result> readArtifacts(AuthzTrans trans, ArtiDAO.Data add) throws OrganizationException { + CertmanValidator v = new CertmanValidator().keys(add); + if(v.err()) { + return Result.err(Result.ERR_BadData,v.errs()); + } + Result> data = artiDAO.read(trans, add); + if(data.notOKorIsEmpty()) { + return data; + } + add = data.value.get(0); + if( trans.user().equals(add.mechid) + || trans.fish(new AAFPermission(add.ns + ".access", "*", "read")) + || trans.fish(new AAFPermission(add.ns+".certman",add.ca,"read")) + || trans.fish(new AAFPermission(add.ns+".certman",add.ca,"request")) + || (trans.org().validate(trans,Organization.Policy.OWNS_MECHID,null,add.mechid))==null) { + return data; + } else { + return Result.err(Result.ERR_Denied,"%s is not %s, is not the sponsor, and doesn't have delegated permission.",trans.user(),add.mechid,add.ns+".certman|"+add.ca+"|read or ...|request"); // note: reason is set by 2nd case, if 1st case misses + } + + } + + public Result> readArtifactsByMechID(AuthzTrans trans, String mechid) throws OrganizationException { + CertmanValidator v = new CertmanValidator(); + v.nullOrBlank("mechid", mechid); + if(v.err()) { + return Result.err(Result.ERR_BadData,v.errs()); + } + String ns = FQI.reverseDomain(mechid); + + String reason; + if(trans.fish(new AAFPermission(ns + ".access", "*", "read")) + || (reason=trans.org().validate(trans,Organization.Policy.OWNS_MECHID,null,mechid))==null) { + return artiDAO.readByMechID(trans, mechid); + } else { + return Result.err(Result.ERR_Denied,reason); // note: reason is set by 2nd case, if 1st case misses + } + + } + + public Result> readArtifactsByMachine(AuthzTrans trans, String machine) { + CertmanValidator v = new CertmanValidator(); + v.nullOrBlank("machine", machine); + if(v.err()) { + return Result.err(Result.ERR_BadData,v.errs()); + } + + // TODO do some checks? + + Result> rv = artiDAO.readByMachine(trans, machine); + return rv; + } + + public Result> readArtifactsByNs(AuthzTrans trans, String ns) { + CertmanValidator v = new CertmanValidator(); + v.nullOrBlank("ns", ns); + if(v.err()) { + return Result.err(Result.ERR_BadData,v.errs()); + } + + // TODO do some checks? + + Result> rv = artiDAO.readByNs(trans, ns); + return rv; + } + + + public Result updateArtifact(AuthzTrans trans, List list) throws OrganizationException { + CertmanValidator v = new CertmanValidator(); + v.artisRequired(list, 1); + if(v.err()) { + return Result.err(Result.ERR_BadData,v.errs()); + } + + // Check if requesting User is Sponsor + //TODO - Shall we do one, or multiples? + for(ArtiDAO.Data add : list) { + // Policy 1: MechID must exist in Org + Identity muser = trans.org().getIdentity(trans, add.mechid); + if(muser == null) { + return Result.err(Result.ERR_Denied,"%s is not valid for %s", add.mechid,trans.org().getName()); + } + + // Policy 2: MechID must have valid Organization Owner + Identity ouser = muser.responsibleTo(); + if(ouser == null) { + return Result.err(Result.ERR_Denied,"%s is not a valid Sponsor for %s at %s", + trans.user(),add.mechid,trans.org().getName()); + } + + // Policy 3: Renewal Days are between 10 and 60 (constants, may be parameterized) + if(add.renewDaysMAX_RENEWAL) { + add.renewDays = MAX_RENEWAL; + } + + // Policy 4: Data is always updated with the latest Sponsor + // Add to Sponsor, to make sure we are always up to date. + add.sponsor = ouser.fullID(); + + // Policy 5: If Notify is blank, set to Owner's Email + if(add.notify==null || add.notify.length()==0) { + add.notify = "mailto:"+ouser.email(); + } + // Policy 6: Only do Domain by Exception + if(add.machine.startsWith("*")) { // Domain set + CA ca = certman.getCA(add.ca); + if(ca==null) { + return Result.err(Result.ERR_BadData, "CA is required in Artifact"); + } + if(!trans.fish(new AAFPermission(ca.getPermType(), add.ca, DOMAIN))) { + return Result.err(Result.ERR_Denied,"Domain Artifacts (%s) requires specific Permission", + add.machine); + } + } + + // Policy 7: only Owner may update info + if(trans.user().equals(add.sponsor)) { + return artiDAO.update(trans, add); + } else { + return Result.err(Result.ERR_Denied,"%s may not update info for %s",trans.user(),muser.fullID()); + } + } + return Result.err(Result.ERR_BadData,"No Artifacts to update"); + } + + public Result deleteArtifact(AuthzTrans trans, String mechid, String machine) throws OrganizationException { + CertmanValidator v = new CertmanValidator(); + v.nullOrBlank("mechid", mechid) + .nullOrBlank("machine", machine); + if(v.err()) { + return Result.err(Result.ERR_BadData,v.errs()); + } + + Result> rlad = artiDAO.read(trans, mechid, machine); + if(rlad.notOKorIsEmpty()) { + return Result.err(Result.ERR_NotFound,"Artifact for %s %s does not exist.",mechid,machine); + } + + return deleteArtifact(trans,rlad.value.get(0)); + } + + private Result deleteArtifact(AuthzTrans trans, ArtiDAO.Data add) throws OrganizationException { + // Policy 1: Record should be delete able only by Existing Sponsor. + String sponsor=null; + Identity muser = trans.org().getIdentity(trans, add.mechid); + if(muser != null) { + Identity ouser = muser.responsibleTo(); + if(ouser!=null) { + sponsor = ouser.fullID(); + } + } + // Policy 1.a: If Sponsorship is deleted in system of Record, then + // accept deletion by sponsor in Artifact Table + if(sponsor==null) { + sponsor = add.sponsor; + } + + String ns = FQI.reverseDomain(add.mechid); + + if(trans.fish(new AAFPermission(ns + ".access", "*", "write")) + || trans.user().equals(sponsor)) { + return artiDAO.delete(trans, add, false); + } + return null; + } + + public Result deleteArtifact(AuthzTrans trans, List list) { + CertmanValidator v = new CertmanValidator().artisRequired(list, 1); + if(v.err()) { + return Result.err(Result.ERR_BadData,v.errs()); + } + + try { + boolean partial = false; + Result result=null; + for(ArtiDAO.Data add : list) { + result = deleteArtifact(trans, add); + if(result.notOK()) { + partial = true; + } + } + if(result == null) { + result = Result.err(Result.ERR_BadData,"No Artifacts to delete"); + } else if(partial) { + result.partialContent(true); + } + return result; + } catch(Exception e) { + return Result.err(e); + } + } + + private String[] compileNotes(List notes) { + String[] rv; + if(notes==null) { + rv = NO_NOTES; + } else { + rv = new String[notes.size()]; + notes.toArray(rv); + } + return rv; + } + + private ByteBuffer getChallenge256SaltedHash(String challenge, int salt) throws NoSuchAlgorithmException { + ByteBuffer bb = ByteBuffer.allocate(Integer.SIZE + challenge.length()); + bb.putInt(salt); + bb.put(challenge.getBytes()); + byte[] hash = Hash.hashSHA256(bb.array()); + return ByteBuffer.wrap(hash); + } +} diff --git a/auth/auth-certman/src/main/java/org/onap/aaf/auth/cm/service/Code.java b/auth/auth-certman/src/main/java/org/onap/aaf/auth/cm/service/Code.java new file mode 100644 index 00000000..ce2ca065 --- /dev/null +++ b/auth/auth-certman/src/main/java/org/onap/aaf/auth/cm/service/Code.java @@ -0,0 +1,45 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.cm.service; + +import org.onap.aaf.auth.cm.AAF_CM; +import org.onap.aaf.auth.cm.facade.Facade1_0; +import org.onap.aaf.auth.env.AuthzTrans; +import org.onap.aaf.auth.rserv.HttpCode; + +public abstract class Code extends HttpCode implements Cloneable { + + public Code(AAF_CM cma, String description, String ... roles) { + super(cma.facade1_0, description, roles); + // Note, the first "Code" will be created with default Facade, "JSON". + // use clone for another Code with XML + } + + + public D clone(Facade1_0 facade) throws Exception { + @SuppressWarnings("unchecked") + D d = (D)clone(); + d.context = facade; + return d; + } + +} diff --git a/auth/auth-certman/src/main/java/org/onap/aaf/auth/cm/validation/CertmanValidator.java b/auth/auth-certman/src/main/java/org/onap/aaf/auth/cm/validation/CertmanValidator.java new file mode 100644 index 00000000..d3ce0ace --- /dev/null +++ b/auth/auth-certman/src/main/java/org/onap/aaf/auth/cm/validation/CertmanValidator.java @@ -0,0 +1,121 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.cm.validation; + +import java.util.List; + +import org.onap.aaf.auth.dao.cass.ArtiDAO; +import org.onap.aaf.auth.dao.cass.ArtiDAO.Data; +import org.onap.aaf.auth.validation.Validator; + +/** + * Validator + * Consistently apply content rules for content (incoming) + * + * Note: We restrict content for usability in URLs (because RESTful service), and avoid + * issues with Regular Expressions, and other enabling technologies. + * @author Jonathan + * + */ +public class CertmanValidator extends Validator{ + // Repeated Msg fragments + private static final String MECHID = "mechid"; + private static final String MACHINE = "machine"; + private static final String ARTIFACT_LIST_IS_NULL = "Artifact List is null."; + private static final String Y = "y."; + private static final String IES = "ies."; + private static final String ENTR = " entr"; + private static final String MUST_HAVE_AT_LEAST = " must have at least "; + private static final String IS_NULL = " is null."; + private static final String ARTIFACTS_MUST_HAVE_AT_LEAST = "Artifacts must have at least "; + + public CertmanValidator nullBlankMin(String name, List list, int min) { + if(list==null) { + msg(name + IS_NULL); + } else { + if(list.size() list, int min) { + if(list==null) { + msg(ARTIFACT_LIST_IS_NULL); + } else { + if(list.size() list, int min) { + if(list==null) { + msg(ARTIFACT_LIST_IS_NULL); + } else { + if(list.size() getNonCriticalExtensionOIDs() { + + return null; + } + + @Override + public byte[] getExtensionValue(String oid) { + + return null; + } + + @Override + public Set getCriticalExtensionOIDs() { + + return null; + } + + @Override + public void verify(PublicKey key, String sigProvider) throws CertificateException, NoSuchAlgorithmException, + InvalidKeyException, NoSuchProviderException, SignatureException { + + + } + + @Override + public void verify(PublicKey key) throws CertificateException, NoSuchAlgorithmException, InvalidKeyException, + NoSuchProviderException, SignatureException { + + + } + + @Override + public String toString() { + + return null; + } + + @Override + public PublicKey getPublicKey() { + + return null; + } + + @Override + public byte[] getEncoded() throws CertificateEncodingException { + + return null; + } + + @Override + public int getVersion() { + + return 0; + } + + @Override + public byte[] getTBSCertificate() throws CertificateEncodingException { + + return null; + } + + @Override + public boolean[] getSubjectUniqueID() { + + return null; + } + + @Override + public Principal getSubjectDN() { + + return null; + } + + @Override + public byte[] getSignature() { + + return null; + } + + @Override + public byte[] getSigAlgParams() { + + return null; + } + + @Override + public String getSigAlgOID() { + + return null; + } + + @Override + public String getSigAlgName() { + + return null; + } + + @Override + public BigInteger getSerialNumber() { + + return null; + } + + @Override + public Date getNotBefore() { + + return null; + } + + @Override + public Date getNotAfter() { + + return null; + } + + @Override + public boolean[] getKeyUsage() { + + return null; + } + + @Override + public boolean[] getIssuerUniqueID() { + + return null; + } + + @Override + public Principal getIssuerDN() { + + return null; + } + + @Override + public int getBasicConstraints() { + + return 0; + } + + @Override + public void checkValidity(Date date) throws CertificateExpiredException, CertificateNotYetValidException { + + + } + + @Override + public void checkValidity() throws CertificateExpiredException, CertificateNotYetValidException { + + } + }; + X509andChain xac = new X509andChain(cert, new ArrayList()); + when(localCA.sign(Mockito.any(Trans.class), Mockito.any(CSRMeta.class))).thenReturn(xac); + certDAO = mock(CachedCertDAO.class, CALLS_REAL_METHODS); + } + + @Test + public void identity_True() throws CertificateException, IOException, CertException { + assertNotNull(localCA.sign(trans, csrMeta)); + } + + + @Test + public void identityNull() throws CertificateException { + try { + assertNotNull(localCA.sign(null, csrMeta)); + } catch (IOException e) { + + e.printStackTrace(); + } catch (CertException e) { + + e.printStackTrace(); + } + } + + @Test + public void identityBothNull() throws CertificateException { + try { + assertNotNull(localCA.sign(null, null)); + } catch (IOException e) { + + e.printStackTrace(); + } catch (CertException e) { + + e.printStackTrace(); + } + } + +} diff --git a/auth/auth-certman/src/test/java/org/onap/aaf/auth/cm/ca/JU_DevlCA.java b/auth/auth-certman/src/test/java/org/onap/aaf/auth/cm/ca/JU_DevlCA.java new file mode 100644 index 00000000..13bf6108 --- /dev/null +++ b/auth/auth-certman/src/test/java/org/onap/aaf/auth/cm/ca/JU_DevlCA.java @@ -0,0 +1,280 @@ +/******************************************************************************* + * ============LICENSE_START==================================================== + * * org.onap.aaf + * * =========================================================================== + * * Copyright © 2017 AT&T Intellectual Property. All rights reserved. + * * =========================================================================== + * * 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==================================================== + * * + * * + ******************************************************************************/ +package org.onap.aaf.auth.cm.ca; + +import static org.junit.Assert.assertNotNull; +import static org.mockito.Mockito.CALLS_REAL_METHODS; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import java.io.IOException; +import java.math.BigInteger; +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; +import java.security.NoSuchProviderException; +import java.security.Principal; +import java.security.PublicKey; +import java.security.SignatureException; +import java.security.cert.CertificateEncodingException; +import java.security.cert.CertificateException; +import java.security.cert.CertificateExpiredException; +import java.security.cert.CertificateNotYetValidException; +import java.security.cert.X509Certificate; +import java.util.Date; +import java.util.Set; + +import javax.security.auth.x500.X500Principal; +import javax.servlet.http.HttpServletRequest; + +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.runners.MockitoJUnitRunner; +import org.onap.aaf.auth.cm.cert.CSRMeta; +import org.onap.aaf.auth.dao.cached.CachedCertDAO; +import org.onap.aaf.cadi.cm.CertException; +import org.onap.aaf.misc.env.Trans; + +//TODO: Gabe [JUnit] Missing class +@RunWith(MockitoJUnitRunner.class) +public class JU_DevlCA { + + @Mock + private static CachedCertDAO certDAO; + + @Mock + private static HttpServletRequest req; + + @Mock + private static CSRMeta csrMeta; + + static Trans trans; + + static X509andChain cert1; + static byte [] name = {1,23,4,54,6,56}; + + private static CA devICA; + + @BeforeClass + public static void setUp() throws CertificateException, CertException, IOException { + String str = "core java api"; + byte[] b = str.getBytes(); + Principal prc = new X500Principal("CN=Duke, OU=JavaSoft, O=Sun Microsystems, C=US"); + req = mock(HttpServletRequest.class); + devICA = mock(CA.class); + X509Certificate cert = new X509Certificate() { + + @Override + public boolean hasUnsupportedCriticalExtension() { + return false; + } + + @Override + public Set getNonCriticalExtensionOIDs() { + + return null; + } + + @Override + public byte[] getExtensionValue(String oid) { + + return null; + } + + @Override + public Set getCriticalExtensionOIDs() { + + return null; + } + + @Override + public void verify(PublicKey key, String sigProvider) throws CertificateException, NoSuchAlgorithmException, + InvalidKeyException, NoSuchProviderException, SignatureException { + + + } + + @Override + public void verify(PublicKey key) throws CertificateException, NoSuchAlgorithmException, InvalidKeyException, + NoSuchProviderException, SignatureException { + + + } + + @Override + public String toString() { + + return null; + } + + @Override + public PublicKey getPublicKey() { + + return null; + } + + @Override + public byte[] getEncoded() throws CertificateEncodingException { + + return null; + } + + @Override + public int getVersion() { + + return 0; + } + + @Override + public byte[] getTBSCertificate() throws CertificateEncodingException { + + return null; + } + + @Override + public boolean[] getSubjectUniqueID() { + + return null; + } + + @Override + public Principal getSubjectDN() { + + return null; + } + + @Override + public byte[] getSignature() { + + return null; + } + + @Override + public byte[] getSigAlgParams() { + + return null; + } + + @Override + public String getSigAlgOID() { + + return null; + } + + @Override + public String getSigAlgName() { + + return null; + } + + @Override + public BigInteger getSerialNumber() { + + return null; + } + + @Override + public Date getNotBefore() { + + return null; + } + + @Override + public Date getNotAfter() { + + return null; + } + + @Override + public boolean[] getKeyUsage() { + + return null; + } + + @Override + public boolean[] getIssuerUniqueID() { + + return null; + } + + @Override + public Principal getIssuerDN() { + + return null; + } + + @Override + public int getBasicConstraints() { + + return 0; + } + + @Override + public void checkValidity(Date date) throws CertificateExpiredException, CertificateNotYetValidException { + + + } + + @Override + public void checkValidity() throws CertificateExpiredException, CertificateNotYetValidException { + + } + }; + when(devICA.sign(Mockito.any(Trans.class), Mockito.any(CSRMeta.class))).thenReturn(cert1); + certDAO = mock(CachedCertDAO.class, CALLS_REAL_METHODS); + } + + @Test + public void identity_True() throws CertificateException, IOException, CertException { + assertNotNull(devICA.sign(trans, csrMeta)); + } + + + @Test + public void identityNull() throws CertificateException { + try { + assertNotNull(devICA.sign(null, csrMeta)); + } catch (IOException e) { + + e.printStackTrace(); + } catch (CertException e) { + + e.printStackTrace(); + } + } + + @Test + public void identityBothNull() throws CertificateException { + try { + assertNotNull(devICA.sign(null, null)); + } catch (IOException e) { + + e.printStackTrace(); + } catch (CertException e) { + + e.printStackTrace(); + } + } + +} diff --git a/auth/auth-certman/src/test/java/org/onap/aaf/auth/cm/cert/JU_BCFactory.java b/auth/auth-certman/src/test/java/org/onap/aaf/auth/cm/cert/JU_BCFactory.java new file mode 100644 index 00000000..856d09c2 --- /dev/null +++ b/auth/auth-certman/src/test/java/org/onap/aaf/auth/cm/cert/JU_BCFactory.java @@ -0,0 +1,128 @@ +/******************************************************************************* + * ============LICENSE_START==================================================== + * * org.onap.aaf + * * =========================================================================== + * * Copyright © 2017 AT&T Intellectual Property. All rights reserved. + * * =========================================================================== + * * 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==================================================== + * * + * * + ******************************************************************************/ +package org.onap.aaf.auth.cm.cert; + +import static org.junit.Assert.assertNotNull; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.security.Key; +import java.security.PrivateKey; +import java.security.PublicKey; + +import org.bouncycastle.operator.OperatorCreationException; +import org.bouncycastle.pkcs.PKCS10CertificationRequest; +import org.junit.BeforeClass; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; +import org.junit.runner.RunWith; +import org.mockito.Mockito; +import org.mockito.runners.MockitoJUnitRunner; +import org.onap.aaf.cadi.cm.CertException; +import org.onap.aaf.misc.env.TimeTaken; +import org.onap.aaf.misc.env.Trans; + +@RunWith(MockitoJUnitRunner.class) +public class JU_BCFactory { + + private static BCFactory bcFactory = new BCFactory(); + + private static BCFactory bcFact; + + private static PrivateKey pk; + + + private static Trans trans; + + + private static PKCS10CertificationRequest req; + + @BeforeClass + public static void setUp() throws IOException { + pk = new XYZKey(); + trans = mock(Trans.class); + req = mock(PKCS10CertificationRequest.class); + when(req.getEncoded()).thenReturn(new byte[1]); + when(trans.start(Mockito.anyString(), Mockito.anyInt())).thenReturn(new TimeTaken(null, 0) { + + @Override + public void output(StringBuilder sb) { + // TODO Auto-generated method stub + + } + }); + bcFact = mock(BCFactory.class); + } + + @Test + public void toStrin() throws OperatorCreationException, IOException, CertException { + assertNotNull(bcFactory.toString(req)); + } + + @Test + public void toStrinMoc() throws OperatorCreationException, IOException, CertException { + assertNotNull(bcFact.toString(req)); + } + + @Rule + public ExpectedException thrown= ExpectedException.none(); + + @Test + public void toCSR() { + try { + assertNotNull(bcFactory.toCSR(trans, new File("/random/path"))); + thrown.expect(FileNotFoundException.class); + } catch (IOException e) { + + e.printStackTrace(); + } + } + +} + +class XYZKey implements Key, PublicKey, PrivateKey { + + int rotValue; + public XYZKey() { + rotValue = 1200213; + } + public String getAlgorithm() { + return "XYZ"; + } + + public String getFormat() { + return "XYZ Special Format"; + } + + public byte[] getEncoded() { + byte b[] = new byte[4]; + b[3] = (byte) ((rotValue << 24) & 0xff); + b[2] = (byte) ((rotValue << 16) & 0xff); + b[1] = (byte) ((rotValue << 8) & 0xff); + b[0] = (byte) ((rotValue << 0) & 0xff); + return b; + } +} diff --git a/auth/auth-certman/src/test/java/org/onap/aaf/auth/cm/cert/JU_CSRMeta.java b/auth/auth-certman/src/test/java/org/onap/aaf/auth/cm/cert/JU_CSRMeta.java new file mode 100644 index 00000000..acf028c6 --- /dev/null +++ b/auth/auth-certman/src/test/java/org/onap/aaf/auth/cm/cert/JU_CSRMeta.java @@ -0,0 +1,88 @@ +/******************************************************************************* + * ============LICENSE_START==================================================== + * * org.onap.aaf + * * =========================================================================== + * * Copyright © 2017 AT&T Intellectual Property. All rights reserved. + * * =========================================================================== + * * 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==================================================== + * * + * * + ******************************************************************************/ +package org.onap.aaf.auth.cm.cert; + +import static org.mockito.Mockito.mock; + +import java.util.List; + +import org.bouncycastle.pkcs.PKCS10CertificationRequest; +import org.junit.BeforeClass; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; +import org.junit.runner.RunWith; +import org.mockito.runners.MockitoJUnitRunner; +import org.onap.aaf.cadi.cm.CertException; +import org.onap.aaf.misc.env.Trans; + +import junit.framework.Assert; + +@RunWith(MockitoJUnitRunner.class) +public class JU_CSRMeta { + + private static CSRMeta csrmeta; + private static Trans trans; + private static PKCS10CertificationRequest req; + + @BeforeClass + public static void setUp() throws CertException { + trans = mock(Trans.class); + List lrdn = RDN.parse('/',"o=ATT Services, Inc/l=St Louis/st=Missouri/c=US"); + + csrmeta = new CSRMeta(lrdn); + } + +// @Test +// public void x500Name() throws IOException { +// +// X500Name x500 = csrmeta.x500Name(); +// assertEquals(x500.toString(),"CN=CN,E=pupleti@ht.com,OU=HAKJH787,O=O,L=L,ST=ST,C=C"); +// } +// +// @Test +// public void initialConversationCert() throws CertificateException, OperatorCreationException, IOException { +// X509Certificate cert = csrmeta.initialConversationCert(trans); +// assertEquals(cert.getBasicConstraints(),-1); +// } +// +// @Test +// public void generateCSR() throws IOException, CertException { +// req = csrmeta.generateCSR(trans); +// assertNotNull(req); +// } + + @Rule + public ExpectedException thrown= ExpectedException.none(); + +// @Test +// public void dump() throws IOException, CertException { +// req = csrmeta.generateCSR(trans); +// csrmeta.dump(req); +// } + + @Test //TODO: Temporary fix AAF-111 + public void netYetTested() { + Assert.fail("Tests not yet implemented"); + } + +} diff --git a/auth/auth-certman/src/test/java/org/onap/aaf/auth/cm/data/JU_CertReq.java b/auth/auth-certman/src/test/java/org/onap/aaf/auth/cm/data/JU_CertReq.java new file mode 100644 index 00000000..f54e36e1 --- /dev/null +++ b/auth/auth-certman/src/test/java/org/onap/aaf/auth/cm/data/JU_CertReq.java @@ -0,0 +1,90 @@ +/******************************************************************************* + * ============LICENSE_START==================================================== + * * org.onap.aaf + * * =========================================================================== + * * Copyright © 2017 AT&T Intellectual Property. All rights reserved. + * * =========================================================================== + * * 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==================================================== + * * + * * + ******************************************************************************/ +package org.onap.aaf.auth.cm.data; + +import static org.junit.Assert.*; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import java.io.IOException; +import java.security.cert.X509Certificate; +import java.util.ArrayList; +import java.util.List; + +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.runners.MockitoJUnitRunner; +import org.onap.aaf.auth.cm.ca.CA; +import org.onap.aaf.auth.cm.ca.X509andChain; +import org.onap.aaf.auth.cm.cert.BCFactory; +import org.onap.aaf.auth.cm.cert.CSRMeta; +import org.onap.aaf.auth.cm.data.CertReq; +import org.onap.aaf.cadi.cm.CertException; +import org.onap.aaf.misc.env.Trans; + +@RunWith(MockitoJUnitRunner.class) +public class JU_CertReq { + + private static BCFactory bcFact; + + private static CSRMeta value; + + private static CertReq req; + + @BeforeClass + public static void setUp() { + bcFact = mock(BCFactory.class); + value = mock(CSRMeta.class); + req = mock(CertReq.class); + + } + +// @Test +// public void getCSRMeta() throws CertException, IOException { +// //req = new CertReq(); +// req.mechid = "1213"; +// List fqdnsas = new ArrayList(); +// fqdnsas.add("String1"); +// List emails = new ArrayList(); +// emails.add("pupleti@hotmail.com"); +// req.emails = emails; +// req.fqdns = fqdnsas; +// req.certAuthority = new CA(null, "testName", "ALL") { +// //TODO: Gabe [JUnit] REREVIEW +// @Override +// public X509andChain sign(Trans trans, CSRMeta csrmeta) throws IOException, CertException { +// +// return null; +// } +// }; +// req.sponsor = "asa@df.co"; +// assertNull(req.getCSRMeta()); +// } + + @Test //TODO: Temporary fix AAF-111 + public void netYetTested() { + fail("Tests not yet implemented"); + } +} diff --git a/auth/auth-certman/src/test/java/org/onap/aaf/auth/cm/facade/JU_FacadeImpl.java b/auth/auth-certman/src/test/java/org/onap/aaf/auth/cm/facade/JU_FacadeImpl.java new file mode 100644 index 00000000..dbfaaeef --- /dev/null +++ b/auth/auth-certman/src/test/java/org/onap/aaf/auth/cm/facade/JU_FacadeImpl.java @@ -0,0 +1,193 @@ +/******************************************************************************* + * ============LICENSE_START==================================================== + * * org.onap.aaf + * * =========================================================================== + * * Copyright © 2017 AT&T Intellectual Property. All rights reserved. + * * =========================================================================== + * * 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==================================================== + * * + * * + ******************************************************************************/ +package org.onap.aaf.auth.cm.facade; + +import static org.junit.Assert.*; +import static org.mockito.Mockito.CALLS_REAL_METHODS; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import java.io.IOException; + +import javax.servlet.ServletOutputStream; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.xml.namespace.QName; +import javax.xml.validation.Schema; + +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mockito; +import org.mockito.runners.MockitoJUnitRunner; +import org.onap.aaf.auth.cm.AAF_CM; +import org.onap.aaf.auth.cm.facade.FacadeImpl; +import org.onap.aaf.auth.cm.mapper.Mapper; +import org.onap.aaf.auth.cm.service.CMService; +import org.onap.aaf.auth.env.AuthzEnv; +import org.onap.aaf.auth.env.AuthzTrans; +import org.onap.aaf.auth.layer.Result; +import org.onap.aaf.cadi.aaf.AAFPermission; +import org.onap.aaf.cadi.aaf.v2_0.AAFLurPerm; +import org.onap.aaf.misc.env.APIException; +import org.onap.aaf.misc.env.Data; +import org.onap.aaf.misc.env.LogTarget; +import org.onap.aaf.misc.env.TimeTaken; +import org.onap.aaf.misc.env.Trans; +import org.onap.aaf.misc.rosetta.env.RosettaDF; +import org.onap.aaf.misc.rosetta.env.RosettaData; + + +@RunWith(MockitoJUnitRunner.class) +public class JU_FacadeImpl { + + private static AuthzTrans trans; + private static HttpServletResponse resp; + private static AAF_CM certman; + private static FacadeImpl hImpl; + private static CMService service; + private Mapper mapper; + private Data.TYPE dataType; + private static AuthzEnv env; + + private static FacadeImpl fImpl; + private static HttpServletRequest req; + + @Before + public void setUp() throws APIException, IOException { + fImpl = mock(FacadeImpl.class); + env = mock(AuthzEnv.class); + resp = mock(HttpServletResponse.class); + req = mock(HttpServletRequest.class); + hImpl = mock(FacadeImpl.class, CALLS_REAL_METHODS); + Result rvd = (Result) mock(Result.class); + trans = mock(AuthzTrans.class); + when(trans.error()).thenReturn(new LogTarget() { + + @Override + public void printf(String fmt, Object... vars) {} + + @Override + public void log(Throwable e, Object... msgs) { + e.getMessage(); + e.printStackTrace(); + msgs.toString(); + + } + + @Override + public void log(Object... msgs) { + } + + @Override + public boolean isLoggable() { + + return false; + } + }); + when(trans.start(Mockito.anyString(), Mockito.anyInt())).thenReturn(new TimeTaken("Now", 1) { + + @Override + public void output(StringBuilder sb) { + + } + }); + when(fImpl.check(Mockito.any(AuthzTrans.class), Mockito.any(HttpServletResponse.class), Mockito.anyString())).thenReturn(rvd); + when(resp.getOutputStream()).thenReturn(new ServletOutputStream() { + + @Override + public void write(int b) throws IOException { + + + } + }); + + } + + @Test + public void check() throws IOException { + AAFPermission ap = new AAFPermission("str1","str3","str2"); + String perms = ap.getInstance(); + assertNotNull(hImpl.check(trans, resp, perms)); + } + + @Test + public void checkNull() throws IOException { + AAFPermission ap = new AAFPermission(null,"Str3","str2"); + String perms = ap.getInstance(); + assertNotNull(hImpl.check(trans, resp, perms)); + } + + @Test + public void checkTwoNull() throws IOException { + AAFPermission ap = new AAFPermission(null,null,"str2"); + String perms = ap.getInstance(); + assertNotNull(fImpl.check(trans, resp, perms)); + } + + @Test + public void checkAllNull() throws IOException { + AAFPermission ap = new AAFPermission(null,null,null); + String perms = ap.getInstance(); + assertNotNull(fImpl.check(trans, resp, perms)); + } + + @Test + public void checkTrans_null() throws IOException { + AAFPermission ap = new AAFPermission("str1","str3","str2"); + String perms = ap.getInstance(); + assertNotNull(hImpl.check(null, resp, perms)); + } + + @Test + public void checkRespNull() throws IOException { + AAFPermission ap = new AAFPermission("str1","str3","str2"); + String perms = ap.getInstance(); + assertNotNull(hImpl.check(trans, null, perms)); + } + + @Test + public void requestCert() { + assertNotNull(hImpl.requestCert(trans, req, resp, null)); + } + + @Test + public void renewCert() { + assertNotNull(hImpl.renewCert(trans, req, resp, true)); + } + + @Test + public void dropCert() { + assertNotNull(hImpl.renewCert(trans, req, resp, true)); + } + + @Test + public void createArtifacts() { + assertNotNull(hImpl.createArtifacts(trans, req, resp)); + } + + @Test + public void readArtifacts() { + assertNotNull(hImpl.readArtifacts(trans, req, resp)); + } +} diff --git a/auth/auth-certman/src/test/java/org/onap/aaf/auth/cm/test/CertmanTest.java b/auth/auth-certman/src/test/java/org/onap/aaf/auth/cm/test/CertmanTest.java new file mode 100644 index 00000000..3faa5bbf --- /dev/null +++ b/auth/auth-certman/src/test/java/org/onap/aaf/auth/cm/test/CertmanTest.java @@ -0,0 +1,170 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ +package org.onap.aaf.auth.cm.test; + +import java.io.InputStream; +import java.net.HttpURLConnection; +import java.net.InetAddress; +import java.net.URI; +import java.security.cert.CertificateException; + +import javax.security.auth.x500.X500Principal; + +import org.junit.After; +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; +import static org.junit.Assert.*; +import org.onap.aaf.auth.env.AuthzEnv; +import org.onap.aaf.cadi.CadiException; +import org.onap.aaf.cadi.Locator; +import org.onap.aaf.cadi.Locator.Item; +import org.onap.aaf.cadi.client.Future; +import org.onap.aaf.cadi.client.Rcli; +import org.onap.aaf.cadi.client.Retryable; +import org.onap.aaf.cadi.cm.Factory; +import org.onap.aaf.cadi.config.SecurityInfoC; +import org.onap.aaf.cadi.http.HBasicAuthSS; +import org.onap.aaf.cadi.http.HMangr; +import org.onap.aaf.cadi.locator.DNSLocator; +import org.onap.aaf.misc.env.APIException; +import org.onap.aaf.misc.env.Data; +import org.onap.aaf.misc.env.Data.TYPE; +import org.onap.aaf.misc.env.util.Chrono; +import org.onap.aaf.misc.rosetta.env.RosettaDF; + +import certman.v1_0.CertInfo; +import certman.v1_0.CertificateRequest; +import junit.framework.Assert; + +public class CertmanTest { + + private static HMangr hman; + private static AuthzEnv env; + private static HBasicAuthSS ss; + private static RosettaDF reqDF; + private static RosettaDF certDF; + + @BeforeClass + public static void setUpBeforeClass() throws Exception { + env = new AuthzEnv(); +// InputStream ris = env.classLoader().getResource("certman.props").openStream(); +// try { +// env.load(ris); +// } finally { +// ris.close(); +// } +// +// Locator loc = new DNSLocator(env, "https", "aaf.it.att.com", "8150"); +// for(Item item = loc.first(); item!=null; item=loc.next(item)) { +// System.out.println(loc.get(item)); +// } +// +// +// SecurityInfoC si = SecurityInfoC.instance(env, HttpURLConnection.class); +// ss = new HBasicAuthSS(si,"m12345@aaf.att.com", +// env.decrypt("enc:gvptdJyo0iKdVZw2rzMb0woxa7YKMdqLuhfQ4OQfZ8k",false)); +// env.decrypt("enc:jFfAnO3mOKb9Gzm2OFysslmXpbnyuAxuoNJK",false), si); +// SecuritySetter ss = new X509SS(si, "aaf"); + +// hman = new HMangr(env,loc); +// +// reqDF = env.newDataFactory(CertificateRequest.class); +// reqDF.out(TYPE.JSON); +// certDF = env.newDataFactory(CertInfo.class); + } + +// @AfterClass +// public static void tearDownAfterClass() throws Exception { +// hman.close(); +// } + + @Before + public void setUp() throws Exception { + + } + + @After + public void tearDown() throws Exception { + } + +// @Test +// public void testX500Name() throws Exception { +// +// for( InetAddress ia : InetAddress.getAllByName("aaf.dev.att.com")) { +// System.out.printf("%s - %s\n", ia.getHostName(), ia.getHostAddress()); +// InetAddress ia1 = InetAddress.getByName(ia.getHostAddress()); +// System.out.printf("%s - %s\n", ia1.getHostName(), ia1.getHostAddress()); +// } +// +// hman.best(ss, new Retryable() { +// @Override +// public Void code(Rcli client) throws APIException, CadiException { +// CertificateRequest cr = new CertificateRequest(); +// cr.setMechid("m12345@aaf.att.com"); +// cr.setSponsor("jg1555"); +// cr.getFqdns().add("mithrilcsp.sbc.com"); +// cr.getFqdns().add("zld01907.vci.att.com"); +// cr.getFqdns().add("aaftest.test.att.com"); +// +// String path = "/cert/local"; // Local Test +//// String path = "/cert/aaf"; // Official CA +// long end=0,start = System.nanoTime(); +// try { +// System.out.println(reqDF.newData().option(Data.PRETTY).load(cr).asString()); +// Future f = client.updateRespondString(path, reqDF, cr); +// if(f.get(10000)) { +// end = System.nanoTime(); +// System.out.println(f.body()); +// CertInfo capi = certDF.newData().in(Data.TYPE.JSON).load(f.body()).asObject(); +// for(String c :capi.getCerts()) { +// for( java.security.cert.Certificate x509 : Factory.toX509Certificate(c)) { +// System.out.println(x509.toString()); +// } +// } +// } else { +// end = System.nanoTime(); +// String msg = "Client returned " + f.code() + ": " + f.body(); +// System.out.println(msg); +// Assert.fail(msg); +// } +// } catch (CertificateException e) { +// throw new CadiException(e); +// } finally { +// System.out.println(Chrono.millisFromNanos(start,end) + " ms"); +// } +// return null; +// } +// }); +// +// +// } +// +// public X500Principal ephemeral() { +// return null; +// } + + @Test //TODO: Temporary fix AAF-111 + public void netYetTested() { + fail("Tests not yet implemented"); + } +} diff --git a/auth/auth-certman/src/test/java/org/onap/aaf/auth/cm/test/JU_KeyMarshaling.java b/auth/auth-certman/src/test/java/org/onap/aaf/auth/cm/test/JU_KeyMarshaling.java new file mode 100644 index 00000000..7b69d286 --- /dev/null +++ b/auth/auth-certman/src/test/java/org/onap/aaf/auth/cm/test/JU_KeyMarshaling.java @@ -0,0 +1,80 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.cm.test; + +import java.io.IOException; +import java.security.KeyPair; +import java.security.PrivateKey; +import java.security.PublicKey; + +import org.junit.AfterClass; +import org.junit.Test; +import org.onap.aaf.auth.env.AuthzEnv; +import org.onap.aaf.auth.env.AuthzTrans; +import org.onap.aaf.cadi.cm.CertException; +import org.onap.aaf.cadi.cm.Factory; + +import junit.framework.Assert; + +public class JU_KeyMarshaling { + + @AfterClass + public static void tearDownAfterClass() throws Exception { + } + + @Test + public void test() { + AuthzEnv env = new AuthzEnv(); + AuthzTrans trans = env.newTrans(); + try { + KeyPair kpair = Factory.generateKeyPair(trans); + String privateString = Factory.toString(trans, kpair.getPrivate()); + System.out.println("Private as base64 encoded as PKCS8 Spec"); + System.out.println(privateString); + + // Take String, and create Private Key + PrivateKey pk = Factory.toPrivateKey(trans, privateString); + Assert.assertEquals(kpair.getPrivate().getAlgorithm(), pk.getAlgorithm()); + Assert.assertEquals(kpair.getPrivate().getFormat(), pk.getFormat()); + Assert.assertEquals(kpair.getPrivate().getEncoded(), pk.getEncoded()); + + + String s = Factory.toString(trans, kpair.getPublic()); + System.out.println("Public as base64 encoded x509 Spec"); + System.out.println(s); + + PublicKey pub = Factory.toPublicKey(trans, s); + Assert.assertEquals(kpair.getPublic().toString(), pub.toString()); + + + } catch (IOException e) { + e.printStackTrace(); + } catch (CertException e) { + e.printStackTrace(); + } finally { + StringBuilder sb = new StringBuilder("=== Timings ===\n"); + trans.auditTrail(1, sb); + System.out.println(sb); + } + } + +} diff --git a/auth/auth-certman/src/test/java/org/onap/aaf/auth/cm/test/JU_SignTest.java b/auth/auth-certman/src/test/java/org/onap/aaf/auth/cm/test/JU_SignTest.java new file mode 100644 index 00000000..93013d3f --- /dev/null +++ b/auth/auth-certman/src/test/java/org/onap/aaf/auth/cm/test/JU_SignTest.java @@ -0,0 +1,109 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.cm.test; + +import java.io.File; +import java.math.BigInteger; +import java.security.KeyPair; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.cert.Certificate; +import java.security.cert.X509Certificate; +import java.security.interfaces.RSAPrivateKey; +import java.security.interfaces.RSAPublicKey; +import java.util.Collection; + +import org.junit.AfterClass; +import org.junit.Assert; +import org.junit.Test; +import static org.junit.Assert.fail; +import org.onap.aaf.auth.env.AuthzEnv; +import org.onap.aaf.auth.env.AuthzTrans; +import org.onap.aaf.cadi.cm.Factory; + +public class JU_SignTest { + + @AfterClass + public static void tearDownAfterClass() throws Exception { + } + + @Test + public void test() throws Exception { + AuthzEnv env = new AuthzEnv(); + AuthzTrans trans = env.newTrans(); + KeyPair kpair = Factory.generateKeyPair(trans); + PrivateKey privateKey = kpair.getPrivate(); + String privateString = Factory.toString(trans, privateKey); + System.out.println("Private as base64 encoded as PKCS8 Spec"); + System.out.println(privateString); + + PublicKey publicKey = kpair.getPublic(); + String publicString = Factory.toString(trans, publicKey); + System.out.println("public as base64 encoded as PKCS8 Spec"); + System.out.println(publicString); + + byte data[] = "Sign this please.".getBytes(); + byte sig[] = Factory.sign(trans, data, privateKey); + System.out.println("Signature"); + System.out.println(Factory.toSignatureString(sig)); + + Assert.assertTrue(Factory.verify(trans, data, sig, publicKey)); + } + +// @Test +// public void test2() throws Exception { +// AuthzEnv env = new AuthzEnv(); +// AuthzTrans trans = env.newTrans(); +// File key = new File("/opt/app/aaf/common/com.att.aaf.key"); +// PrivateKey privKey = Factory.toPrivateKey(trans, key); +// RSAPrivateKey rPrivKey = (RSAPrivateKey)privKey; +// BigInteger privMod, pubMod; +// System.out.println((privMod = rPrivKey.getModulus()).toString(16)); +// +// byte data[] = "Sign this please.".getBytes(); +// byte sig[] = Factory.sign(trans, data, privKey); +// System.out.println("Signature"); +// System.out.println(Factory.toSignatureString(sig)); +// +// +// File crt = new File("/opt/app/aaf/common/com.att.aaf.crt"); +// Collection x509s = Factory.toX509Certificate(trans, crt); +// X509Certificate cert = null; +// for(Certificate c : x509s) { +// cert = (X509Certificate)c; +// break; +// } +// PublicKey pubKey = cert.getPublicKey(); +// RSAPublicKey rPubKey = (RSAPublicKey)pubKey; +// +// System.out.println((pubMod = rPubKey.getModulus()).toString(16)); +// +// Assert.assertTrue(Factory.verify(trans, data, sig, pubKey)); +// Assert.assertEquals(privMod,pubMod); +// +// } + + @Test //TODO: Temporary fix AAF-111 + public void netYetTested() { + fail("Tests not yet implemented"); + } +} diff --git a/auth/auth-client/.gitignore b/auth/auth-client/.gitignore new file mode 100644 index 00000000..7a112ea5 --- /dev/null +++ b/auth/auth-client/.gitignore @@ -0,0 +1,5 @@ +/.classpath +/.settings +/bin +/target +/.project diff --git a/auth/auth-client/pom.xml b/auth/auth-client/pom.xml new file mode 100644 index 00000000..56672b16 --- /dev/null +++ b/auth/auth-client/pom.xml @@ -0,0 +1,131 @@ + + + + 4.0.0 + + + aaf-auth-client + AAF Auth Client + XSD Generated classes for AAF Auth + org.onap.aaf.auth + 2.10-SNAPSHOT + jar + + + UTF-8 + true + + + + + Jonathan Gathman + jonathan.gathman@att.com + ATT + + Architect + Lead Developer + + + + Gabe Maurer + gabe.maurer@att.com + ATT + + Developer + + + + Ian Howell + ian.howell@att.com + ATT + + Developer + + + + + + + + junit + junit + 4.10 + test + + + + + + + + org.jvnet.jaxb2.maven2 + maven-jaxb2-plugin + 0.8.2 + + + + generate + + + + + src/main/xsd + + + + + org.apache.maven.plugins + maven-deploy-plugin + 2.5 + + false + + + + + org.apache.maven.plugins + maven-compiler-plugin + 2.3.2 + + 1.6 + 1.6 + + + + + + + + nexus + attarch-releases + http://mavencentral.it.att.com:8084/nexus/content/repositories/attarch-releases + + + nexus + attarch-snapshots + http://mavencentral.it.att.com:8084/nexus/content/repositories/attarch-snapshots + + + + + diff --git a/auth/auth-client/src/main/xsd/aaf_2_0.xsd b/auth/auth-client/src/main/xsd/aaf_2_0.xsd new file mode 100644 index 00000000..b4b1ba9c --- /dev/null +++ b/auth/auth-client/src/main/xsd/aaf_2_0.xsd @@ -0,0 +1,547 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/auth/auth-client/src/main/xsd/aaf_oauth2.xsd b/auth/auth-client/src/main/xsd/aaf_oauth2.xsd new file mode 100644 index 00000000..22283184 --- /dev/null +++ b/auth/auth-client/src/main/xsd/aaf_oauth2.xsd @@ -0,0 +1,141 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/auth/auth-client/src/main/xsd/certman_1_0.xsd b/auth/auth-client/src/main/xsd/certman_1_0.xsd new file mode 100644 index 00000000..19c698b9 --- /dev/null +++ b/auth/auth-client/src/main/xsd/certman_1_0.xsd @@ -0,0 +1,169 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/auth/auth-client/src/main/xsd/certman_2_0.xsd b/auth/auth-client/src/main/xsd/certman_2_0.xsd new file mode 100644 index 00000000..35389402 --- /dev/null +++ b/auth/auth-client/src/main/xsd/certman_2_0.xsd @@ -0,0 +1,169 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/auth/auth-client/src/main/xsd/locate_1_0.xsd b/auth/auth-client/src/main/xsd/locate_1_0.xsd new file mode 100644 index 00000000..209e3bf4 --- /dev/null +++ b/auth/auth-client/src/main/xsd/locate_1_0.xsd @@ -0,0 +1,79 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/auth/auth-cmd/.gitignore b/auth/auth-cmd/.gitignore new file mode 100644 index 00000000..5aee8092 --- /dev/null +++ b/auth/auth-cmd/.gitignore @@ -0,0 +1,6 @@ +/.settings +/bin +/logs +/target +/.classpath +/.project diff --git a/auth/auth-cmd/pom.xml b/auth/auth-cmd/pom.xml new file mode 100644 index 00000000..4b051889 --- /dev/null +++ b/auth/auth-cmd/pom.xml @@ -0,0 +1,89 @@ + + + + + 4.0.0 + + org.onap.aaf.auth + parent + 2.1.0-SNAPSHOT + ../pom.xml + + + aaf-auth-cmd + AAF Auth Command + Command Line Processor for AAF Auth + jar + + + false + + + + + Jonathan Gathman + jonathan.gathman@att.com + ATT + + Architect + Lead Developer + + + + Gabe Maurer + gabe.maurer@att.com + ATT + + Developer + + + + Ian Howell + ian.howell@att.com + ATT + + Developer + + + + + + + + org.onap.aaf.cadi + aaf-cadi-aaf + + + + org.onap.aaf.auth + aaf-auth-core + + + + jline + jline + 2.14.2 + + + + diff --git a/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/AAFcli.java b/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/AAFcli.java new file mode 100644 index 00000000..e8069b8e --- /dev/null +++ b/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/AAFcli.java @@ -0,0 +1,647 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.cmd; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileReader; +import java.io.InputStreamReader; +import java.io.OutputStreamWriter; +import java.io.PrintWriter; +import java.io.Reader; +import java.io.Writer; +import java.net.HttpURLConnection; +import java.net.URI; +import java.util.ArrayList; +import java.util.List; + +import org.onap.aaf.auth.cmd.mgmt.Mgmt; +import org.onap.aaf.auth.cmd.ns.NS; +import org.onap.aaf.auth.cmd.perm.Perm; +import org.onap.aaf.auth.cmd.role.Role; +import org.onap.aaf.auth.cmd.user.User; +import org.onap.aaf.auth.common.Define; +import org.onap.aaf.auth.env.AuthzEnv; +import org.onap.aaf.cadi.Access; +import org.onap.aaf.cadi.CadiException; +import org.onap.aaf.cadi.Locator; +import org.onap.aaf.cadi.PropAccess; +import org.onap.aaf.cadi.SecuritySetter; +import org.onap.aaf.cadi.Access.Level; +import org.onap.aaf.cadi.aaf.v2_0.AAFLocator; +import org.onap.aaf.cadi.client.Retryable; +import org.onap.aaf.cadi.config.Config; +import org.onap.aaf.cadi.config.SecurityInfoC; +import org.onap.aaf.cadi.http.HBasicAuthSS; +import org.onap.aaf.cadi.http.HMangr; +import org.onap.aaf.cadi.sso.AAFSSO; +import org.onap.aaf.misc.env.APIException; + +import jline.console.ConsoleReader; + +public class AAFcli { + private static final String HTTPS = "https://"; + protected static PrintWriter pw; + protected HMangr hman; + // Storage for last reused client. We can do this + // because we're technically "single" threaded calls. + public Retryable prevCall; + + protected SecuritySetter ss; +// protected AuthzEnv env; + private boolean close; + private List cmds; + + // Lex State + private ArrayList expect = new ArrayList(); + private boolean verbose = true; + private int delay; + private SecurityInfoC si; + private boolean request = false; + private String force = null; + private boolean gui = false; + // Package on purpose + Access access; + AuthzEnv env; + + private static int TIMEOUT = Integer.parseInt(Config.AAF_CONN_TIMEOUT_DEF); + private static boolean isConsole = false; + private static boolean isTest = false; + private static boolean showDetails = false; + private static boolean ignoreDelay = false; + private static int globalDelay=0; + + public static int timeout() { + return TIMEOUT; + } + + // Create when only have Access + public AAFcli(Access access, Writer wtr, HMangr hman, SecurityInfoC si, SecuritySetter ss) throws APIException { + this(access,new AuthzEnv(access.getProperties()),wtr,hman, si,ss); + } + + public AAFcli(Access access, AuthzEnv env, Writer wtr, HMangr hman, SecurityInfoC si, SecuritySetter ss) throws APIException { + this.env = env; + this.access = access; + this.ss = ss; + this.hman = hman; + this.si = si; + if (wtr instanceof PrintWriter) { + pw = (PrintWriter) wtr; + close = false; + } else { + pw = new PrintWriter(wtr); + close = true; + } + + + /* + * Create Cmd Tree + */ + cmds = new ArrayList(); + + Role role = new Role(this); + cmds.add(new Help(this, cmds)); + cmds.add(new Version(this)); + cmds.add(new Perm(role)); + cmds.add(role); + cmds.add(new User(this)); + cmds.add(new NS(this)); + cmds.add(new Mgmt(this)); + } + + public void verbose(boolean v) { + verbose = v; + } + + public void close() { + if (hman != null) { + hman.close(); + hman = null; + } + if (close) { + pw.close(); + } + } + + public boolean eval(String line) throws Exception { + if (line.length() == 0) { + return true; + } else if (line.startsWith("#")) { + pw.println(line); + return true; + } + + String[] largs = argEval(line); + int idx = 0; + + // Variable replacement + StringBuilder sb = null; + while (idx < largs.length) { + int e = 0; + for (int v = largs[idx].indexOf("@["); v >= 0; v = largs[idx].indexOf("@[", v + 1)) { + if (sb == null) { + sb = new StringBuilder(); + } + sb.append(largs[idx], e, v); + if ((e = largs[idx].indexOf(']', v)) >= 0) { + String p = access.getProperty(largs[idx].substring(v + 2, e),null); + if(p==null) { + p = System.getProperty(largs[idx].substring(v+2,e)); + } + ++e; + if (p != null) { + sb.append(p); + } + } + } + if (sb != null && sb.length() > 0) { + sb.append(largs[idx], e, largs[idx].length()); + largs[idx] = sb.toString(); + sb.setLength(0); + } + ++idx; + } + + idx = 0; + boolean rv = true; + while (rv && idx < largs.length) { + // Allow Script to change Credential + if (!gui) { + if("as".equalsIgnoreCase(largs[idx])) { + if (largs.length > ++idx) { + // get Password from Props with ID as Key + String user = largs[idx++]; + int colon = user.indexOf(':'); + String pass; + if (colon > 0) { + pass = user.substring(colon + 1); + user = user.substring(0, colon); + } else { + pass = access.getProperty(user, null); + } + if (pass != null) { + pass = access.decrypt(pass, false); + access.getProperties().put(user, pass); + ss = new HBasicAuthSS(si, user, pass); + pw.println("as " + user); + } else { // get Pass from System Properties, under name of + // Tag + pw.println("ERROR: No password set for " + user); + rv = false; + } + continue; + } + } else if ("expect".equalsIgnoreCase(largs[idx])) { + expect.clear(); + if (largs.length > idx++) { + if (!"nothing".equals(largs[idx])) { + for (String str : largs[idx].split(",")) { + try { + if ("Exception".equalsIgnoreCase(str)) { + expect.add(-1); + } else { + expect.add(Integer.parseInt(str)); + } + } catch (NumberFormatException e) { + throw new CadiException("\"expect\" should be followed by Number"); + } + } + ++idx; + } + } + continue; + // Sleep, typically for reports, to allow DB to update + // Milliseconds + + } else if ("sleep".equalsIgnoreCase(largs[idx])) { + Integer t = Integer.parseInt(largs[++idx]); + pw.println("sleep " + t); + Thread.sleep(t); + ++idx; + continue; + } else if ("delay".equalsIgnoreCase(largs[idx])) { + delay = Integer.parseInt(largs[++idx]); + pw.println("delay " + delay); + ++idx; + continue; + } else if ("pause".equalsIgnoreCase(largs[idx])) { + pw.println("Press to continue..."); + ++idx; + new BufferedReader(new InputStreamReader(System.in)).readLine(); + continue; + } else if ("exit".equalsIgnoreCase(largs[idx])) { + pw.println("Exiting..."); + return false; + } + + } + + if("REQUEST".equalsIgnoreCase(largs[idx])) { + request=true; + ++idx; + } else if("FORCE".equalsIgnoreCase(largs[idx])) { + force="true"; + ++idx; + } else if("DETAILS".equalsIgnoreCase(largs[idx])) { + showDetails=true; + ++idx; + } else if ("set".equalsIgnoreCase(largs[idx])) { + while (largs.length > ++idx) { + int equals = largs[idx].indexOf('='); + String tag, value; + if (equals < 0) { + tag = largs[idx]; + value = access.getProperty(Config.AAF_APPPASS,null); + if(value==null) { + break; + } else { + value = access.decrypt(value, false); + if(value==null) { + break; + } + access.getProperties().put(tag, value); + pw.println("set " + tag + " "); + } + } else { + tag = largs[idx].substring(0, equals); + value = largs[idx].substring(++equals); + pw.println("set " + tag + ' ' + value); + } + boolean isTrue = "TRUE".equalsIgnoreCase(value); + if("FORCE".equalsIgnoreCase(tag)) { + force = value; + } else if("REQUEST".equalsIgnoreCase(tag)) { + request = isTrue; + } else if("DETAILS".equalsIgnoreCase(tag)) { + showDetails = isTrue; + } else { + access.getProperties().put(tag, value); + } + } + continue; + // Allow Script to indicate if Failure is what is expected + } + + int ret = 0; + for (Cmd c : cmds) { + if (largs[idx].equalsIgnoreCase(c.getName())) { + if (verbose) { + pw.println(line); + if (expect.size() > 0) { + pw.print("** Expect "); + boolean first = true; + for (Integer i : expect) { + if (first) { + first = false; + } else { + pw.print(','); + } + pw.print(i); + } + pw.println(" **"); + } + } + try { + ret = c.exec(++idx, largs); + if (delay+globalDelay > 0) { + Thread.sleep(delay+globalDelay); + } + } catch (Exception e) { + if (expect.contains(-1)) { + pw.println(e.getMessage()); + ret = -1; + } else { + throw e; + } + } finally { + clearSingleLineProperties(); + } + rv = expect.isEmpty() ? true : expect.contains(ret); + if (verbose) { + if (rv) { + pw.println(); + } else { + pw.print("!!! Unexpected Return Code: "); + pw.print(ret); + pw.println(", VALIDATE OUTPUT!!!"); + } + } + return rv; + } + } + pw.write("Unknown Instruction \""); + pw.write(largs[idx]); + pw.write("\"\n"); + idx = largs.length;// always end after one command + } + return rv; + } + + private String[] argEval(String line) { + StringBuilder sb = new StringBuilder(); + ArrayList arr = new ArrayList(); + boolean start = true; + char quote = 0; + char last = 0; + for (int i = 0; i < line.length(); ++i) { + char ch; + if (Character.isWhitespace(ch = line.charAt(i))) { + if (start || last==',') { + continue; // trim + } else if (quote != 0) { + sb.append(ch); + } else { + arr.add(sb.toString()); + sb.setLength(0); + start = true; + } + } else if (ch == '\'' || ch == '"') { // toggle + if (quote == ch) { + quote = 0; + } else { + quote = ch; + } + } else if(ch=='|' && quote==0) { + arr.add(sb.toString()); + sb.setLength(0); + start = true; + } else { + start = false; + sb.append(ch); + last = ch; + } + } + if (sb.length() > 0) { + arr.add(sb.toString()); + } + + String[] rv = new String[arr.size()]; + arr.toArray(rv); + return rv; + } + + public static void keyboardHelp() { + System.out.println("'C-' means hold the ctrl key down while pressing the next key."); + System.out.println("'M-' means hold the alt key down while pressing the next key."); + System.out.println("For instance, C-b means hold ctrl key and press b, M-b means hold alt and press b\n"); + + System.out.println("Basic Keybindings:"); + System.out.println("\tC-l - clear screen"); + System.out.println("\tC-a - beginning of line"); + System.out.println("\tC-e - end of line"); + System.out.println("\tC-b - backward character (left arrow also works)"); + System.out.println("\tM-b - backward word"); + System.out.println("\tC-f - forward character (right arrow also works)"); + System.out.println("\tM-f - forward word"); + System.out.println("\tC-d - delete character under cursor"); + System.out.println("\tM-d - delete word forward"); + System.out.println("\tM-backspace - delete word backward"); + System.out.println("\tC-k - delete from cursor to end of line"); + System.out.println("\tC-u - delete entire line, regardless of cursor position\n"); + + System.out.println("Command History:"); + System.out.println("\tC-r - search backward in history (repeating C-r continues the search)"); + System.out.println("\tC-p - move backwards through history (up arrow also works)"); + System.out.println("\tC-n - move forwards through history (down arrow also works)\n"); + + } + + /** + * @param args + */ + public static void main(String[] args) { + int rv = 0; + + try { + AAFSSO aafsso = new AAFSSO(args); + try { + PropAccess access = aafsso.access(); + Define.set(access); + AuthzEnv env = new AuthzEnv(access); + + StringBuilder err = aafsso.err(); + String noexit = access.getProperty("no_exit"); + if (err != null) { + err.append("to continue..."); + System.err.println(err); + if(noexit!=null) { + System.exit(1); + } + } + + Reader rdr = null; + boolean exitOnFailure = true; + /* + * Check for "-" options anywhere in command line + */ + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < args.length; ++i) { + if ("-i".equalsIgnoreCase(args[i])) { + rdr = new InputStreamReader(System.in); + // } else if("-o".equalsIgnoreCase(args[i])) { + // // shall we do something different? Output stream is + // already done... + } else if ("-f".equalsIgnoreCase(args[i])) { + if (args.length > i + 1) { + rdr = new FileReader(args[++i]); + } + } else if ("-a".equalsIgnoreCase(args[i])) { + exitOnFailure = false; + } else if ("-c".equalsIgnoreCase(args[i])) { + isConsole = true; + } else if ("-s".equalsIgnoreCase(args[i]) && args.length > i + 1) { + access.setProperty(Cmd.STARTDATE, args[++i]); + } else if ("-e".equalsIgnoreCase(args[i]) && args.length > i + 1) { + access.setProperty(Cmd.ENDDATE, args[++i]); + } else if ("-t".equalsIgnoreCase(args[i])) { + isTest = true; + } else if ("-d".equalsIgnoreCase(args[i])) { + showDetails = true; + } else if ("-n".equalsIgnoreCase(args[i])) { + ignoreDelay = true; + } else { + if (sb.length() > 0) { + sb.append(' '); + } + sb.append(args[i]); + } + } + + SecurityInfoC si = SecurityInfoC.instance(access, HttpURLConnection.class); + Locator loc; + String aafUrl = access.getProperty(Config.AAF_URL); + if(aafUrl==null) { + aafsso.setLogDefault(); + aafsso.setStdErrDefault(); + aafUrl=AAFSSO.cons.readLine("aaf_url=%s", HTTPS); + if(aafUrl.length()==0) { + System.exit(0); + } else if(!aafUrl.startsWith(HTTPS)) { + aafUrl=HTTPS+aafUrl; + } + aafsso.addProp(Config.AAF_URL, aafUrl); + } + // Note, with AAF Locator, this may not longer be necessary 3/2018 Jonathan + if(!aafsso.loginOnly()) { + try { + loc = new AAFLocator(si,new URI(aafUrl)); + } catch (Throwable t) { + aafsso.setStdErrDefault(); + throw t; + } finally { + // Other Access is done writing to StdOut and StdErr, reset Std out + aafsso.setLogDefault(); + } + + TIMEOUT = Integer.parseInt(access.getProperty(Config.AAF_CONN_TIMEOUT, Config.AAF_CONN_TIMEOUT_DEF)); + HMangr hman = new HMangr(access, loc).readTimeout(TIMEOUT).apiVersion("2.0"); + + if(access.getProperty(Config.AAF_DEFAULT_REALM)==null) { + access.log(Level.ERROR, Config.AAF_DEFAULT_REALM,"is required"); + } + + + AAFcli aafcli = new AAFcli(access,env, new OutputStreamWriter(System.out), hman, si, + new HBasicAuthSS(si,aafsso.user(), access.decrypt(aafsso.enc_pass(),false))); + if(!ignoreDelay) { + File delay = new File("aafcli.delay"); + if(delay.exists()) { + BufferedReader br = new BufferedReader(new FileReader(delay)); + try { + globalDelay = Integer.parseInt(br.readLine()); + } catch(Exception e) { + access.log(Level.DEBUG,e); + } finally { + br.close(); + } + } + } + try { + if (isConsole) { + System.out.println("Type 'help' for short help or 'help -d' for detailed help with aafcli commands"); + System.out.println("Type '?' for help with command line editing"); + System.out.println("Type 'q', 'quit', or 'exit' to quit aafcli\n"); + + ConsoleReader reader = new ConsoleReader(); + try { + reader.setPrompt("aafcli > "); + + String line; + while ((line = reader.readLine()) != null) { + showDetails = (line.contains("-d"))?true:false; + + if (line.equalsIgnoreCase("quit") || line.equalsIgnoreCase("q") || line.equalsIgnoreCase("exit")) { + break; + } else if (line.equalsIgnoreCase("--help -d") || line.equalsIgnoreCase("help -d") + || line.equalsIgnoreCase("help")) { + line = "--help"; + } else if (line.equalsIgnoreCase("cls")) { + reader.clearScreen(); + continue; + } else if (line.equalsIgnoreCase("?")) { + keyboardHelp(); + continue; + } + try { + aafcli.eval(line); + pw.flush(); + } catch (Exception e) { + pw.println(e.getMessage()); + pw.flush(); + } + } + } finally { + reader.close(); + } + } else if (rdr != null) { + BufferedReader br = new BufferedReader(rdr); + String line; + while ((line = br.readLine()) != null) { + if (!aafcli.eval(line) && exitOnFailure) { + rv = 1; + break; + } + } + } else { // just run the command line + aafcli.verbose(false); + if (sb.length() == 0) { + sb.append("--help"); + } + rv = aafcli.eval(sb.toString()) ? 0 : 1; + } + + } finally { + aafcli.close(); + + // Don't close if No Reader, or it's a Reader of Standard In + if (rdr != null && !(rdr instanceof InputStreamReader)) { + rdr.close(); + } + } + } + aafsso.writeFiles(); + } finally { + aafsso.close(); + } + + } catch (MessageException e) { + System.out.println("MessageException caught"); + + System.err.println(e.getMessage()); + } catch (Throwable e) { + e.printStackTrace(System.err); + } + System.exit(rv); + } + + public boolean isTest() { + return AAFcli.isTest; + } + + public boolean isDetailed() { + return AAFcli.showDetails; + } + + public String typeString(Class cls, boolean json) { + return "application/" + cls.getSimpleName() + "+" + (json ? "json" : "xml") + ";version=" + hman.apiVersion(); + } + + public String forceString() { + return force; + } + + public boolean addRequest() { + return request; + } + + public void clearSingleLineProperties() { + force = null; + request = false; + showDetails = false; + } + + public void gui(boolean b) { + gui = b; + } + +} diff --git a/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/BaseCmd.java b/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/BaseCmd.java new file mode 100644 index 00000000..0bfefd21 --- /dev/null +++ b/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/BaseCmd.java @@ -0,0 +1,68 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.cmd; + +import java.util.ArrayList; +import java.util.List; + +import org.onap.aaf.cadi.CadiException; +import org.onap.aaf.cadi.LocatorException; +import org.onap.aaf.misc.env.APIException; + + +public class BaseCmd extends Cmd { + protected List cmds; + + public BaseCmd(AAFcli aafcli, String name, Param ... params) { + super(aafcli, null, name, params); + cmds = new ArrayList(); + } + + public BaseCmd(CMD parent, String name, Param ... params) { + super(parent.aafcli, parent, name, params); + cmds = new ArrayList(); + } + + + @Override + public int _exec( int idx, final String ... args) throws CadiException, APIException, LocatorException { + if(args.length-idx<1) { + pw().println(build(new StringBuilder(),null).toString()); + } else { + String s = args[idx]; + String name; + Cmd empty = null; + for(Cmd c: cmds) { + name = c.getName(); + if(name==null && empty==null) { // Mark with Command is null, and take the first one. + empty = c; + } else if(s.equalsIgnoreCase(c.getName())) + return c.exec(idx+1, args); + } + if(empty!=null) { + return empty.exec(idx, args); // If name is null, don't account for it on command line. Jonathan 4-29 + } + pw().println("Instructions not understood."); + } + return 0; + } +} diff --git a/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/Cmd.java b/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/Cmd.java new file mode 100644 index 00000000..9ee321e7 --- /dev/null +++ b/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/Cmd.java @@ -0,0 +1,541 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.cmd; + +import java.io.PrintWriter; +import java.io.StringReader; +import java.sql.Date; +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Comparator; +import java.util.GregorianCalendar; +import java.util.List; +import java.util.Stack; +import java.util.concurrent.ConcurrentHashMap; + +import org.onap.aaf.auth.env.AuthzEnv; +import org.onap.aaf.auth.org.OrganizationException; +import org.onap.aaf.auth.rserv.HttpMethods; +import org.onap.aaf.cadi.Access; +import org.onap.aaf.cadi.CadiException; +import org.onap.aaf.cadi.LocatorException; +import org.onap.aaf.cadi.client.Future; +import org.onap.aaf.cadi.client.Rcli; +import org.onap.aaf.cadi.client.Retryable; +import org.onap.aaf.cadi.config.Config; +import org.onap.aaf.cadi.http.HMangr; +import org.onap.aaf.misc.env.APIException; +import org.onap.aaf.misc.env.Data.TYPE; +import org.onap.aaf.misc.env.util.Chrono; +import org.onap.aaf.misc.rosetta.env.RosettaDF; + +import aaf.v2_0.Error; +import aaf.v2_0.History; +import aaf.v2_0.History.Item; +import aaf.v2_0.Request; + + +public abstract class Cmd { + private static final DateFormat dateFmt = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss:SSS"); + protected static final String BLANK = ""; + protected static final String COMMA = ","; // for use in splits + + protected static final int lineLength = 80; + + private final static String hformat = "%-23s %-5s %-20s %-35s\n"; + + public static final String STARTDATE = "startdate"; + public static final String ENDDATE = "enddate"; + + private String name; + private final Param[] params; + private int required; + protected final Cmd parent; + protected final List children; + private final static ConcurrentHashMap,RosettaDF> dfs = new ConcurrentHashMap,RosettaDF>(); + public final AAFcli aafcli; + protected Access access; + private AuthzEnv env; + private final String defaultRealm; + + public Cmd(AAFcli aafcli, String name, Param ... params) { + this(aafcli,null, name,params); + } + + public Cmd(Cmd parent, String name, Param ... params) { + this(parent.aafcli,parent, name,params); + } + + Cmd(AAFcli aafcli, Cmd parent, String name, Param ... params) { + this.parent = parent; + this.aafcli = aafcli; + this.env = aafcli.env; + this.access = aafcli.access; + if(parent!=null) { + parent.children.add(this); + } + children = new ArrayList(); + this.params = params; + this.name = name; + required=0; + for(Param p : params) { + if(p.required) { + ++required; + } + } + + String temp = access.getProperty(Config.AAF_DEFAULT_REALM,null); + if(temp!=null && !temp.startsWith("@")) { + defaultRealm = '@' + temp; + } else { + defaultRealm=""; + } + } + + public final int exec(int idx, String ... args) throws CadiException, APIException, LocatorException { + if(args.length-idx cls,boolean head) { + final String smeth = meth.name(); + if(head) { + sb.append('\n'); + detailLine(sb,indent,"APIs:"); + } + indent+=2; + multiChar(sb,indent,' ',0); + sb.append(smeth); + sb.append(' '); + sb.append(pathInfo); + String cliString = aafcli.typeString(cls,true); + if(indent+smeth.length()+pathInfo.length()+cliString.length()+2>80) { + sb.append(" ..."); + multiChar(sb,indent+3+smeth.length(),' ',0); + } else { // same line + sb.append(' '); + } + sb.append(cliString); + } + + protected void multiChar(StringBuilder sb, int length, char c, int indent) { + sb.append('\n'); + for(int i=0;i ": "] "); + } + + boolean first = true; + for(Cmd child : children) { + if(!(child instanceof DeprecatedCMD)) { + if(first) { + first = false; + } else if(detail==null) { + multiChar(sb,indent,' ',0); + } else { + // Write parents for Detailed Report + Stack stack = new Stack(); + for(Cmd c = child.parent;c!=null;c=c.parent) { + if(c.name!=null) { + stack.push(c.name); + } + } + if(!stack.isEmpty()) { + sb.append(" "); + while(!stack.isEmpty()) { + sb.append(stack.pop()); + sb.append(' '); + } + } + } + child.build(sb,detail); + if(detail!=null) { + child.detailedHelp(4, detail); + // If Child wrote something, then add, bracketing by lines + if(detail.length()>0) { + multiChar(sb,80,'-',2); + sb.append(detail); + sb.append('\n'); + multiChar(sb,80,'-',2); + sb.append('\n'); + detail.setLength(0); // reuse + } else { + sb.append('\n'); + } + } + } + } + return sb; + } + + protected void error(Future future) { + StringBuilder sb = new StringBuilder("Failed"); + String desc = future.body(); + int code = future.code(); + if(desc==null || desc.length()==0) { + withCode(sb,code); + } else if(desc.startsWith("{")) { + StringReader sr = new StringReader(desc); + try { + // Note: 11-18-2013, JG1555. This rather convoluted Message Structure required by TSS Restful Specs, reflecting "Northbound" practices. + Error err = getDF(Error.class).newData().in(TYPE.JSON).load(sr).asObject(); + sb.append(" ["); + sb.append(err.getMessageId()); + sb.append("]: "); + String messageBody = err.getText(); + List vars = err.getVariables(); + int pipe; + for (int varCounter=0;varCounter= 0) { + if((pipe = var.indexOf('|'))>=0) { // In AAF, we use a PIPE for Choice + if (aafcli.isTest()) { + String expiresStr = var.substring(pipe); + var = var.replace(expiresStr, "[Placeholder]"); + } else { + StringBuilder varsb = new StringBuilder(var); + varsb.deleteCharAt(pipe); + var = varsb.toString(); + } + messageBody = messageBody.replace("%" + varCounter, varCounter-1 + ") " + var); + } else { + messageBody = messageBody.replace("%" + varCounter, var); + } + } + } + sb.append(messageBody); + } catch (Exception e) { + withCode(sb,code); + sb.append(" (Note: Details cannot be obtained from Error Structure)"); + } + } else if(desc.startsWith("")){ // Core Jetty, etc sends HTML for Browsers + withCode(sb,code); + } else { + sb.append(" with code "); + sb.append(code); + sb.append(", "); + sb.append(desc); + } + pw().println(sb); + } + + + private void withCode(StringBuilder sb, Integer code) { + sb.append(" with code "); + sb.append(code); + switch(code) { + case 401: + sb.append(" (HTTP Not Authenticated)"); + break; + case 403: + sb.append(" (HTTP Forbidden)"); + break; + case 404: + sb.append(" (HTTP Not Found)"); + break; + default: + } + } + + /** + * Consistently set start and end dates from Requests (all derived from Request) + * @param req + */ + protected void setStartEnd(Request req) { + // Set Start/End Dates, if exist + String str; + if((str = access.getProperty(Cmd.STARTDATE,null))!=null) { + req.setStart(Chrono.timeStamp(Date.valueOf(str))); + } + + if((str = access.getProperty(Cmd.ENDDATE,null))!=null) { + req.setEnd(Chrono.timeStamp(Date.valueOf(str))); + } + } + + /** + * For Derived classes, who have ENV in this parent + * + * @param cls + * @return + * @throws APIException + */ + protected RosettaDF getDF(Class cls) throws APIException { + return getDF(env,cls); + } + + /** + * This works well, making available for GUI, etc. + * @param env + * @param cls + * @return + * @throws APIException + */ + @SuppressWarnings("unchecked") + public static RosettaDF getDF(AuthzEnv env, Class cls) throws APIException { + RosettaDF rdf = (RosettaDF)dfs.get(cls); + if(rdf == null) { + rdf = env.newDataFactory(cls); + dfs.put(cls, rdf); + } + return rdf; + } + + public void activity(History history, String header) { + if (history.getItem().isEmpty()) { + int start = header.indexOf('['); + if (start >= 0) { + pw().println("No Activity Found for " + header.substring(start)); + } + } else { + pw().println(header); + for(int i=0;i items = history.getItem(); + java.util.Collections.sort(items, new Comparator() { + @Override + public int compare(Item o1, Item o2) { + return o2.getTimestamp().compare(o1.getTimestamp()); + } + }); + + for(History.Item item : items) { + GregorianCalendar gc = item.getTimestamp().toGregorianCalendar(); + pw().format(hformat, + dateFmt.format(gc.getTime()), + item.getTarget(), + item.getUser(), + item.getMemo()); + } + } + } + + /** + * Turn String Array into a | delimited String + * @param options + * @return + */ + public static String optionsToString(String[] options) { + StringBuilder sb = new StringBuilder(); + boolean first = true; + for(String s : options) { + if(first) { + first = false; + } else { + sb.append('|'); + } + sb.append(s); + } + return sb.toString(); + } + + /** + * return which index number the Option matches. + * + * throws an Exception if not part of this Option Set + * + * @param options + * @param test + * @return + * @throws Exception + */ + public int whichOption(String[] options, String test) throws CadiException { + for(int i=0;i RET same(Retryable retryable) throws APIException, CadiException, LocatorException { + // We're storing in AAFCli, because we know it's always the same, and single threaded + if(aafcli.prevCall!=null) { + retryable.item(aafcli.prevCall.item()); + retryable.lastClient=aafcli.prevCall.lastClient; + } + + RET ret = aafcli.hman.same(aafcli.ss,retryable); + + // Store last call in AAFcli, because Cmds are all different instances. + aafcli.prevCall = retryable; + return ret; + } + + public RET all(Retryable retryable) throws APIException, CadiException, LocatorException { + this.setQueryParamsOn(retryable.lastClient); + return aafcli.hman.all(aafcli.ss,retryable); + } + + public RET oneOf(Retryable retryable,String host) throws APIException, CadiException, LocatorException { + this.setQueryParamsOn(retryable.lastClient); + return aafcli.hman.oneOf(aafcli.ss,retryable,true,host); + } + + protected PrintWriter pw() { + return AAFcli.pw; + } + + public String getName() { + return name; + } + + public void reportHead(String ... str) { + pw().println(); + boolean first = true; + int i=0; + for(String s : str) { + if(first) { + if(++i>1) { + first = false; + pw().print("["); + } + } else { + pw().print("] ["); + } + pw().print(s); + } + if(!first) { + pw().print(']'); + } + pw().println(); + reportLine(); + } + + public String reportColHead(String format, String ... args) { + pw().format(format,(Object[])args); + reportLine(); + return format; + } + + public void reportLine() { + for(int i=0;i rcli) { + StringBuilder sb=null; + String force; + if((force=aafcli.forceString())!=null) { + sb = new StringBuilder("force="); + sb.append(force); + } + if(aafcli.addRequest()) { + if(sb==null) { + sb = new StringBuilder("future=true"); + } else { + sb.append("&future=true"); + } + } + if(sb!=null && rcli!=null) { + rcli.setQueryParams(sb.toString()); + } + } +// +// /** +// * If Force is set, will return True once only, then revert to "FALSE". +// * +// * @return +// */ +// protected String checkForce() { +// if(TRUE.equalsIgnoreCase(env.getProperty(FORCE, FALSE))) { +// env.setProperty(FORCE, FALSE); +// return "true"; +// } +// return FALSE; +// } + + public String toString() { + StringBuilder sb = new StringBuilder(); + if(parent==null) { // ultimate parent + build(sb,null); + return sb.toString(); + } else { + return parent.toString(); + } + } + +// private String getOrgRealm() { +// return ; +// } +// + /** + * Appends shortID with Realm, but only when allowed by Organization + * @throws OrganizationException + */ + public String fullID(String id) { + if(id != null) { + if (id.indexOf('@') < 0) { + id+=defaultRealm; + } else { + return id; // is already a full ID + } + } + return id; + } +} diff --git a/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/DeprecatedCMD.java b/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/DeprecatedCMD.java new file mode 100644 index 00000000..b13c7333 --- /dev/null +++ b/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/DeprecatedCMD.java @@ -0,0 +1,53 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.cmd; + +import org.onap.aaf.cadi.CadiException; +import org.onap.aaf.cadi.LocatorException; +import org.onap.aaf.misc.env.APIException; + + +/** + * Use this class to deprecate methods and features, by pointing to the new + * usages. + * + * These commands will not show up in Help + * @author Jonathan + * + * @param + */ +public class DeprecatedCMD extends BaseCmd { + private String text; + + @SuppressWarnings("unchecked") + public DeprecatedCMD(Cmd cmd, String name, String text) { + super((X)cmd,name); + this.text = text; + } + + @Override + public int _exec(int _idx, final String ... args) throws CadiException, APIException, LocatorException { + pw().println(text); + return _idx; + } + +} diff --git a/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/Help.java b/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/Help.java new file mode 100644 index 00000000..ca10915d --- /dev/null +++ b/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/Help.java @@ -0,0 +1,118 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.cmd; + +import java.util.List; + +import org.onap.aaf.cadi.CadiException; +import org.onap.aaf.cadi.LocatorException; +import org.onap.aaf.misc.env.APIException; + +public class Help extends Cmd { + private List cmds; + + public Help(AAFcli aafcli, List cmds) { + super(aafcli, "--help", + new Param("-d (more details)", false), + new Param("command",false)); + this.cmds = cmds; + } + + @Override + public int _exec( int _idx, final String ... args) throws CadiException, APIException, LocatorException { + int idx = _idx; + boolean first = true; + StringBuilder sb = new StringBuilder("AAF Command Line Tool"); + StringBuilder details; + multiChar(sb, 21, '-',0); + sb.append("\n SingleLine Commands"); + multiChar(sb, 21, '-',2); + sb.append("\n force - add to regular commands to override depency checks"); + sb.append("\n details - add to role list or perm list commands for rich format"); + multiChar(sb, 48, '-',2); + // if details !=null, then extra details are written to it. + details = aafcli.isDetailed()?new StringBuilder():null; + + String comp = args.length>idx?args[idx++]:null; + if("help".equalsIgnoreCase(comp)) { + build(sb,null); + detailedHelp(4, sb); + sb.append('\n'); + } else { + for(Cmd c : cmds) { + if(!(c instanceof DeprecatedCMD)) { + if(comp!=null) { + if(comp.equals(c.getName())) { + multiChar(sb,2,' ',0); + c.build(sb,details); + } + } else { + if(first) { + first=false; + } else { + multiChar(sb,80,'-',2); + } + multiChar(sb,2,' ',0); + c.build(sb,details); + if(details!=null) { + c.detailedHelp(4, sb); + // multiChar(sb,80,'-',2); + } + } + } + } + } + pw().println(sb.toString()); + return 200 /*HttpStatus.OK_200*/; + } + + @Override + public void detailedHelp(int _indent, StringBuilder sb) { + int indent = _indent; + detailLine(sb,indent,"To print main help, enter \"aafcli\" or \"aafcli --help \""); + detailLine(sb,indent,"To print narrow the help content, enter sub-entries after aafcli,"); + detailLine(sb,indent+2,"i.e. \"aafcli perm\""); + detailLine(sb,indent,"To see version of AAF CLI, enter \"aafcli --version \""); + sb.append('\n'); + detailLine(sb,indent,"State Commands: change variables or credentials between calls."); + indent+=4; + detailLine(sb,indent,"set = - Set any System Property to a new value"); + detailLine(sb,indent,"as - Change Credentials. Password may be encrypted"); + detailLine(sb,indent,"expect [int]* - In test mode, check for proper HTTP Status Codes"); + detailLine(sb,indent,"sleep - Wait for seconds"); + detailLine(sb,indent,"force - force deletions that have relationships"); + detailLine(sb,indent,"details - cause list commands (role, perm) to print rich format"); + detailLine(sb,indent," - In GUI CmdLine, use HourGlass option (top right)"); + sb.append('\n'); + detailLine(sb,indent-4,"CmdLine Arguments: change behavior of the aafcli program"); + detailLine(sb,indent,"-i - Read commands from Shell Standard Input"); + detailLine(sb,indent,"-f - Read commands from a file"); + detailLine(sb,indent,"-r - Clear Command Line SSO credential"); + detailLine(sb,indent,"-a - In test mode, do not stop execution on unexpected error"); + detailLine(sb,indent,"-t - Test Mode will not print variable fields that could break tc runs"); + detailLine(sb,indent+6,"such as expiration dates of a credential"); + detailLine(sb,indent,"-s - Request specific Start Date (not immediately)"); + detailLine(sb,indent+6,"Format YYYY-MM-DD. Can also be set with \"set " + Cmd.STARTDATE + "=\""); + detailLine(sb,indent,"-e - Set Expiration/End Date, where commands support"); + detailLine(sb,indent+6,"Format YYYY-MM-DD. Can also be set with \"set " + Cmd.ENDDATE + "=\""); + } +} diff --git a/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/MessageException.java b/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/MessageException.java new file mode 100644 index 00000000..3ed81222 --- /dev/null +++ b/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/MessageException.java @@ -0,0 +1,46 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +/** + * + */ +package org.onap.aaf.auth.cmd; + +/** + * An Exception designed simply to give End User message, no stack trace + * + * @author Jonathan + * + */ +public class MessageException extends Exception { + /** + * + */ + private static final long serialVersionUID = 8143933588878259048L; + + /** + * @param Message + */ + public MessageException(String msg) { + super(msg); + } + +} diff --git a/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/Param.java b/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/Param.java new file mode 100644 index 00000000..0d79df0a --- /dev/null +++ b/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/Param.java @@ -0,0 +1,37 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.cmd; + +public class Param { + public final String tag; + public final boolean required; + + /** + * + * @param t + * @param b + */ + public Param(String t, boolean required) { + tag = t; + this.required=required; + } +} diff --git a/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/Version.java b/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/Version.java new file mode 100644 index 00000000..316c5334 --- /dev/null +++ b/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/Version.java @@ -0,0 +1,43 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.cmd; + +import org.onap.aaf.cadi.CadiException; +import org.onap.aaf.cadi.LocatorException; +import org.onap.aaf.cadi.config.Config; +import org.onap.aaf.misc.env.APIException; + +public class Version extends Cmd { + + + public Version(AAFcli aafcli) { + super(aafcli, "--version"); + } + + @Override + protected int _exec(int idx, String... args) throws CadiException, APIException, LocatorException { + pw().println("AAF Command Line Tool"); + String version = access.getProperty(Config.AAF_DEFAULT_VERSION, "2.0"); + pw().println("Version: " + version); + return 200 /*HttpStatus.OK_200;*/; + } +} diff --git a/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/mgmt/Cache.java b/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/mgmt/Cache.java new file mode 100644 index 00000000..cd153537 --- /dev/null +++ b/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/mgmt/Cache.java @@ -0,0 +1,32 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.cmd.mgmt; + +import org.onap.aaf.auth.cmd.BaseCmd; +import org.onap.aaf.misc.env.APIException; + +public class Cache extends BaseCmd { + public Cache(Mgmt mgmt) throws APIException { + super(mgmt, "cache"); + cmds.add(new Clear(this)); + } +} diff --git a/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/mgmt/Clear.java b/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/mgmt/Clear.java new file mode 100644 index 00000000..a18c1c48 --- /dev/null +++ b/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/mgmt/Clear.java @@ -0,0 +1,85 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.cmd.mgmt; + +import org.onap.aaf.auth.cmd.AAFcli; +import org.onap.aaf.auth.cmd.Cmd; +import org.onap.aaf.auth.cmd.Param; +import org.onap.aaf.auth.common.Define; +import org.onap.aaf.auth.rserv.HttpMethods; +import org.onap.aaf.cadi.CadiException; +import org.onap.aaf.cadi.LocatorException; +import org.onap.aaf.cadi.client.Future; +import org.onap.aaf.cadi.client.Rcli; +import org.onap.aaf.cadi.client.Retryable; +import org.onap.aaf.misc.env.APIException; + +/** + * + * @author Jonathan + * + */ +public class Clear extends Cmd { + public Clear(Cache parent) { + super(parent,"clear", + new Param("name[,name]*",true)); + } + + @Override + public int _exec(int _idx, String ... args) throws CadiException, APIException, LocatorException { + int idx = _idx; + int rv=409; + for(final String name : args[idx++].split(COMMA)) { + rv = all(new Retryable() { + @Override + public Integer code(Rcli client) throws APIException, CadiException { + int rv = 409; + Future fp = client.delete( + "/mgmt/cache/"+name, + Void.class + ); + if(fp.get(AAFcli.timeout())) { + pw().println("Cleared Cache for " + name + " on " + client); + rv=200; + } else { + if(rv==409)rv = fp.code(); + error(fp); + } + return rv; + } + }); + } + return rv; + } + + @Override + public void detailedHelp(int _indent, StringBuilder sb) { + int indent = _indent; + detailLine(sb,indent,"Clear the cache for certain tables"); + indent+=2; + detailLine(sb,indent,"name - name of table or 'all'"); + detailLine(sb,indent+14,"Must have admin rights to '" + Define.ROOT_NS() + '\''); + indent-=2; + api(sb,indent,HttpMethods.DELETE,"mgmt/cache/:name",Void.class,true); + } + +} diff --git a/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/mgmt/Deny.java b/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/mgmt/Deny.java new file mode 100644 index 00000000..b8fc4a23 --- /dev/null +++ b/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/mgmt/Deny.java @@ -0,0 +1,101 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.cmd.mgmt; + +import org.onap.aaf.auth.cmd.AAFcli; +import org.onap.aaf.auth.cmd.BaseCmd; +import org.onap.aaf.auth.cmd.Cmd; +import org.onap.aaf.auth.cmd.Param; +import org.onap.aaf.cadi.CadiException; +import org.onap.aaf.cadi.LocatorException; +import org.onap.aaf.cadi.client.Future; +import org.onap.aaf.cadi.client.Rcli; +import org.onap.aaf.cadi.client.Retryable; +import org.onap.aaf.cadi.config.Config; +import org.onap.aaf.misc.env.APIException; + +public class Deny extends BaseCmd { + private final static String[] options = {"add","del"}; + + public Deny(Mgmt mgmt) throws APIException { + super(mgmt, "deny"); + cmds.add(new DenySomething(this,"ip","ipv4or6[,ipv4or6]*")); + cmds.add(new DenySomething(this,"id","identity[,identity]*")); + } + + public class DenySomething extends Cmd { + + private boolean isID; + + public DenySomething(Deny deny, String type, String repeatable) { + super(deny, type, + new Param(optionsToString(options),true), + new Param(repeatable,true)); + isID = "id".equals(type); + } + + @Override + protected int _exec(int _idx, String... args) throws CadiException, APIException, LocatorException { + int idx = _idx; + String action = args[idx++]; + final int option = whichOption(options, action); + int rv=409; + for(final String name : args[idx++].split(COMMA)) { + final String append; + if(isID && name.indexOf("@")<0) { + append='@'+ access.getProperty(Config.AAF_DEFAULT_REALM,null); + } else { + append = ""; + } + final String path = "/mgmt/deny/"+getName() + '/'+ name + append; + rv = all(new Retryable() { + @Override + public Integer code(Rcli client) throws APIException, CadiException { + int rv = 409; + Future fp; + String resp; + switch(option) { + case 0: + fp = client.create(path, Void.class); + resp = " added"; + break; + default: + fp = client.delete(path, Void.class); + resp = " deleted"; + } + if(fp.get(AAFcli.timeout())) { + pw().println(name + append + resp + " on " + client); + rv=fp.code(); + } else { + if(rv==409)rv = fp.code(); + error(fp); + } + return rv; + } + }); + } + return rv; + } + + } + +} diff --git a/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/mgmt/Log.java b/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/mgmt/Log.java new file mode 100644 index 00000000..80ad8a46 --- /dev/null +++ b/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/mgmt/Log.java @@ -0,0 +1,108 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.cmd.mgmt; + +import org.onap.aaf.auth.cmd.AAFcli; +import org.onap.aaf.auth.cmd.BaseCmd; +import org.onap.aaf.auth.cmd.Param; +import org.onap.aaf.auth.common.Define; +import org.onap.aaf.auth.rserv.HttpMethods; +import org.onap.aaf.cadi.CadiException; +import org.onap.aaf.cadi.LocatorException; +import org.onap.aaf.cadi.client.Future; +import org.onap.aaf.cadi.client.Rcli; +import org.onap.aaf.cadi.client.Retryable; +import org.onap.aaf.cadi.config.Config; +import org.onap.aaf.misc.env.APIException; + +public class Log extends BaseCmd { + private final static String[] options = {"add","del"}; + + public Log(Mgmt mgmt) throws APIException { + super(mgmt, "log", + new Param(optionsToString(options),true), + new Param("id[,id]*",true)); + } + + @Override + public int _exec(int _idx, String ... args) throws CadiException, APIException, LocatorException { + int rv=409; + int idx = _idx; + final int option = whichOption(options, args[idx++]); + + for(String name : args[idx++].split(COMMA)) { + final String fname; + if(name.indexOf("@")<0) { + fname=name+'@'+ access.getProperty(Config.AAF_DEFAULT_REALM,null); + } else { + fname = name; + } + + rv = all(new Retryable() { + @Override + public Integer code(Rcli client) throws APIException, CadiException { + int rv = 409; + Future fp; + String str = "/mgmt/log/id/"+fname; + String msg; + switch(option) { + case 0: + fp = client.create(str,Void.class); + msg = "Added"; + break; + case 1: + fp = client.delete(str,Void.class); + msg = "Deleted"; + break; + default: + fp = null; + msg = "Ignored"; + } + + if(fp!=null) { + if(fp.get(AAFcli.timeout())) { + pw().println(msg + " Special Log for " + fname + " on " + client); + rv=200; + } else { + if(rv==409)rv = fp.code(); + error(fp); + } + return rv; + } + return rv; + } + }); + } + return rv; + } + + @Override + public void detailedHelp(int _indent, StringBuilder sb) { + int indent = _indent; + detailLine(sb,indent,"Clear the cache for certain tables"); + indent+=2; + detailLine(sb,indent,"name - name of table or 'all'"); + detailLine(sb,indent+14,"Must have admin rights to '" + Define.ROOT_NS() + '\''); + indent-=2; + api(sb,indent,HttpMethods.DELETE,"mgmt/cache/:name",Void.class,true); + } +} diff --git a/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/mgmt/Mgmt.java b/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/mgmt/Mgmt.java new file mode 100644 index 00000000..6b5e2d66 --- /dev/null +++ b/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/mgmt/Mgmt.java @@ -0,0 +1,36 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.cmd.mgmt; + +import org.onap.aaf.auth.cmd.AAFcli; +import org.onap.aaf.auth.cmd.BaseCmd; +import org.onap.aaf.misc.env.APIException; + +public class Mgmt extends BaseCmd { + public Mgmt(AAFcli aafcli) throws APIException { + super(aafcli, "mgmt"); + cmds.add(new Cache(this)); + cmds.add(new Deny(this)); + cmds.add(new Log(this)); + cmds.add(new Session(this)); + } +} diff --git a/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/mgmt/SessClear.java b/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/mgmt/SessClear.java new file mode 100644 index 00000000..cfd2fa8d --- /dev/null +++ b/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/mgmt/SessClear.java @@ -0,0 +1,83 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.cmd.mgmt; + +import org.onap.aaf.auth.cmd.AAFcli; +import org.onap.aaf.auth.cmd.Cmd; +import org.onap.aaf.auth.cmd.Param; +import org.onap.aaf.auth.common.Define; +import org.onap.aaf.auth.rserv.HttpMethods; +import org.onap.aaf.cadi.CadiException; +import org.onap.aaf.cadi.LocatorException; +import org.onap.aaf.cadi.client.Future; +import org.onap.aaf.cadi.client.Rcli; +import org.onap.aaf.cadi.client.Retryable; +import org.onap.aaf.misc.env.APIException; + +/** + * p + * @author Jonathan + * + */ +public class SessClear extends Cmd { + public SessClear(Session parent) { + super(parent,"clear", + new Param("machine",true)); + } + + @Override + public int _exec(int idx, String ... args) throws CadiException, APIException, LocatorException { + int rv=409; + String machine = args[idx++]; + rv = oneOf(new Retryable() { + @Override + public Integer code(Rcli client) throws APIException, CadiException { + int rv = 409; + Future fp = client.delete( + "/mgmt/dbsession", + Void.class + ); + if(fp.get(AAFcli.timeout())) { + pw().println("Cleared DBSession on " + client); + rv=200; + } else { + if(rv==409)rv = fp.code(); + error(fp); + } + return rv; + } + },machine); + return rv; + } + + @Override + public void detailedHelp(int _indent, StringBuilder sb) { + int indent = _indent; + detailLine(sb,indent,"Clear the cache for certain tables"); + indent+=2; + detailLine(sb,indent,"name - name of table or 'all'"); + detailLine(sb,indent+14,"Must have admin rights to " + Define.ROOT_NS() + '\''); + indent-=2; + api(sb,indent,HttpMethods.DELETE,"mgmt/cache/:name",Void.class,true); + } + +} diff --git a/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/mgmt/Session.java b/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/mgmt/Session.java new file mode 100644 index 00000000..5929caea --- /dev/null +++ b/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/mgmt/Session.java @@ -0,0 +1,32 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.cmd.mgmt; + +import org.onap.aaf.auth.cmd.BaseCmd; +import org.onap.aaf.misc.env.APIException; + +public class Session extends BaseCmd { + public Session(Mgmt mgmt) throws APIException { + super(mgmt, "dbsession"); + cmds.add(new SessClear(this)); + } +} diff --git a/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/ns/Admin.java b/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/ns/Admin.java new file mode 100644 index 00000000..363c7482 --- /dev/null +++ b/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/ns/Admin.java @@ -0,0 +1,103 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.cmd.ns; + +import org.onap.aaf.auth.cmd.AAFcli; +import org.onap.aaf.auth.cmd.BaseCmd; +import org.onap.aaf.auth.cmd.Param; +import org.onap.aaf.auth.rserv.HttpMethods; +import org.onap.aaf.cadi.CadiException; +import org.onap.aaf.cadi.LocatorException; +import org.onap.aaf.cadi.client.Future; +import org.onap.aaf.cadi.client.Rcli; +import org.onap.aaf.cadi.client.Retryable; +import org.onap.aaf.misc.env.APIException; + +public class Admin extends BaseCmd { + private final static String[] options = {"add","del"}; + + public Admin(NS ns) throws APIException { + super(ns,"admin", + new Param(optionsToString(options),true), + new Param("ns-name",true), + new Param("id[,id]*",true) + ); + } + + @Override + public int _exec(int _idx, final String ... args) throws CadiException, APIException, LocatorException { + int idx = _idx; + final int option = whichOption(options, args[idx++]); + final String ns = args[idx++]; + final String ids[] = args[idx++].split(","); + + return same(new Retryable() { + @Override + public Integer code(Rcli client) throws CadiException, APIException { + Future fp = null; + for(String id : ids) { + id = fullID(id); + String verb; + switch(option) { + case 0: + fp = client.create("/authz/ns/"+ns+"/admin/"+id,Void.class); + verb = " added to "; + break; + case 1: + fp = client.delete("/authz/ns/"+ns+"/admin/"+id,Void.class); + verb = " deleted from "; + break; + default: + throw new CadiException("Bad Argument"); + }; + + if(fp.get(AAFcli.timeout())) { + pw().append("Admin "); + pw().append(id); + pw().append(verb); + pw().println(ns); + } else { + error(fp); + return fp.code(); + } + + } + return fp==null?500:fp.code(); + } + }); + } + + @Override + public void detailedHelp(int _indent, StringBuilder sb) { + int indent = _indent; + detailLine(sb,indent,"Add or Delete Administrator to/from Namespace"); + indent+=4; + detailLine(sb,indent,"name - Name of Namespace"); + detailLine(sb,indent,"id - Credential of Person(s) to be Administrator"); + sb.append('\n'); + detailLine(sb,indent,"aafcli will call API on each ID presented."); + indent-=4; + api(sb,indent,HttpMethods.POST,"authz/ns//admin/",Void.class,true); + api(sb,indent,HttpMethods.DELETE,"authz/ns//admin/",Void.class,false); + } + +} diff --git a/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/ns/Attrib.java b/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/ns/Attrib.java new file mode 100644 index 00000000..cc0d2586 --- /dev/null +++ b/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/ns/Attrib.java @@ -0,0 +1,113 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.cmd.ns; + +import org.onap.aaf.auth.cmd.AAFcli; +import org.onap.aaf.auth.cmd.BaseCmd; +import org.onap.aaf.auth.cmd.Param; +import org.onap.aaf.auth.rserv.HttpMethods; +import org.onap.aaf.cadi.CadiException; +import org.onap.aaf.cadi.LocatorException; +import org.onap.aaf.cadi.client.Future; +import org.onap.aaf.cadi.client.Rcli; +import org.onap.aaf.cadi.client.Retryable; +import org.onap.aaf.misc.env.APIException; + +public class Attrib extends BaseCmd { + private final static String[] options = {"add","upd","del"}; + + public Attrib(NS ns) throws APIException { + super(ns,"attrib", + new Param(optionsToString(options),true), + new Param("ns-name",true), + new Param("key",true), + new Param("value",false) + ); + } + + @Override + public int _exec(final int idx, final String ... args) throws CadiException, APIException, LocatorException { + final int option = whichOption(options, args[idx]); + final String ns = args[idx+1]; + final String key = args[idx+2]; + final String value; + if(option!=2) { + if(args.length<=idx+3) { + throw new CadiException("Not added: Need more Data"); + } + value = args[idx+3]; + } else { + value = ""; + } + + return same(new Retryable() { + @Override + public Integer code(Rcli client) throws CadiException, APIException { + Future fp = null; + String message; + switch(option) { + case 0: + fp = client.create("/authz/ns/"+ns+"/attrib/"+key+'/'+value,Void.class); + message = String.format("Add Attrib %s=%s to %s", + key,value,ns); + break; + case 1: + fp = client.update("/authz/ns/"+ns+"/attrib/"+key+'/'+value); + message = String.format("Update Attrib %s=%s for %s", + key,value,ns); + break; + case 2: + fp = client.delete("/authz/ns/"+ns+"/attrib/"+key,Void.class); + message = String.format("Attrib %s deleted from %s", + key,ns); + break; + default: + throw new CadiException("Bad Argument"); + }; + + if(fp.get(AAFcli.timeout())) { + pw().println(message); + } else { + error(fp); + return fp.code(); + } + + return fp==null?500:fp.code(); + } + }); + } + + @Override + public void detailedHelp(int _indent, StringBuilder sb) { + int indent = _indent; + detailLine(sb,indent,"Add or Delete Administrator to/from Namespace"); + indent+=4; + detailLine(sb,indent,"name - Name of Namespace"); + detailLine(sb,indent,"id - Credential of Person(s) to be Administrator"); + sb.append('\n'); + detailLine(sb,indent,"aafcli will call API on each ID presented."); + indent-=4; + api(sb,indent,HttpMethods.POST,"authz/ns//admin/",Void.class,true); + api(sb,indent,HttpMethods.DELETE,"authz/ns//admin/",Void.class,false); + } + +} diff --git a/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/ns/Create.java b/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/ns/Create.java new file mode 100644 index 00000000..a62d5531 --- /dev/null +++ b/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/ns/Create.java @@ -0,0 +1,123 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.cmd.ns; + +import org.onap.aaf.auth.cmd.AAFcli; +import org.onap.aaf.auth.cmd.Cmd; +import org.onap.aaf.auth.cmd.Param; +import org.onap.aaf.auth.rserv.HttpMethods; +import org.onap.aaf.cadi.CadiException; +import org.onap.aaf.cadi.LocatorException; +import org.onap.aaf.cadi.client.Future; +import org.onap.aaf.cadi.client.Rcli; +import org.onap.aaf.cadi.client.Retryable; +import org.onap.aaf.misc.env.APIException; + +import aaf.v2_0.NsRequest; + +/** + * @author Jonathan + * + */ +public class Create extends Cmd { + private static final String COMMA = ","; + + public Create(NS parent) { + super(parent,"create", + new Param("ns-name",true), + new Param("owner (id[,id]*)",true), + new Param("admin (id[,id]*)",false)); + } + + @Override + public int _exec(int _idx, final String ... args) throws CadiException, APIException, LocatorException { + int idx = _idx; + + final NsRequest nr = new NsRequest(); + + nr.setName(args[idx++]); + String[] responsible = args[idx++].split(COMMA); + for(String s : responsible) { + nr.getResponsible().add(fullID(s)); + } + String[] admin; + if(args.length>idx) { + admin = args[idx++].split(COMMA); + } else { + admin = responsible; + } + for(String s : admin) { + nr.getAdmin().add(fullID(s)); + } + + // Set Start/End commands + setStartEnd(nr); + + return same(new Retryable() { + @Override + public Integer code(Rcli client) throws CadiException, APIException { + // Requestable + setQueryParamsOn(client); + Future fp = client.create( + "/authz/ns", + getDF(NsRequest.class), + nr + ); + if(fp.get(AAFcli.timeout())) { + pw().println("Created Namespace"); + } else { + if(fp.code()==202) { + pw().println("Namespace Creation Accepted, but requires Approvals before actualizing"); + } else { + error(fp); + } + } + return fp.code(); + } + }); + } + + @Override + public void detailedHelp(int _indent, StringBuilder sb) { + int indent = _indent; + detailLine(sb,indent,"Create a Namespace"); + indent+=2; + detailLine(sb,indent,"name - Namespaces are dot-delimited, ex com.att.myapp"); + detailLine(sb,indent+14,"and must be created with parent credentials."); + detailLine(sb,indent+14,"Ex: to create com.att.myapp, you must be admin for com.att"); + detailLine(sb,indent+14,"or com"); + detailLine(sb,indent,"owner - This is the person(s) who is responsible for the "); + detailLine(sb,indent+14,"app. These person or persons receive Notifications and"); + detailLine(sb,indent+14,"approves Requests regarding this Namespace. Companies have"); + detailLine(sb,indent+14,"Policies as to who may take on this responsibility"); + detailLine(sb,indent,"admin - These are the people who are allowed to make changes on"); + detailLine(sb,indent+14,"the Namespace, including creating Roles, Permissions"); + detailLine(sb,indent+14,"and Credentials"); + sb.append('\n'); + detailLine(sb,indent,"Namespaces can be created even though there are Roles/Permissions which"); + detailLine(sb,indent,"start with the requested sub-namespace. They are reassigned to the"); + detailLine(sb,indent,"Child Namespace"); + indent-=2; + api(sb,indent,HttpMethods.POST,"authz/ns",NsRequest.class,true); + } + +} diff --git a/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/ns/Delete.java b/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/ns/Delete.java new file mode 100644 index 00000000..19915f4e --- /dev/null +++ b/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/ns/Delete.java @@ -0,0 +1,89 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.cmd.ns; + +import org.onap.aaf.auth.cmd.AAFcli; +import org.onap.aaf.auth.cmd.Cmd; +import org.onap.aaf.auth.cmd.Param; +import org.onap.aaf.auth.rserv.HttpMethods; +import org.onap.aaf.cadi.CadiException; +import org.onap.aaf.cadi.LocatorException; +import org.onap.aaf.cadi.client.Future; +import org.onap.aaf.cadi.client.Rcli; +import org.onap.aaf.cadi.client.Retryable; +import org.onap.aaf.misc.env.APIException; + +/** + * p + * @author Jonathan + * + */ +public class Delete extends Cmd { + public Delete(NS parent) { + super(parent,"delete", + new Param("ns-name",true)); + } + + @Override + public int _exec(final int idx, final String ... args) throws CadiException, APIException, LocatorException { + return same(new Retryable() { + @Override + public Integer code(Rcli client) throws CadiException, APIException { + int index = idx; + StringBuilder path = new StringBuilder("/authz/ns/"); + path.append(args[index++]); + + // Send "Force" if set + setQueryParamsOn(client); + Future fp = client.delete(path.toString(),Void.class); + + if(fp.get(AAFcli.timeout())) { + pw().println("Deleted Namespace"); + } else { + error(fp); + } + return fp.code(); + } + }); + } + + @Override + public void detailedHelp(int _indent, StringBuilder sb) { + int indent = _indent; + detailLine(sb,indent,"Delete a Namespace"); + indent+=4; + detailLine(sb,indent,"Namespaces cannot normally be deleted when there are still credentials,"); + detailLine(sb,indent,"permissions or roles associated with them. These can be deleted"); + detailLine(sb,indent,"automatically by setting \"force\" property."); + detailLine(sb,indent,"i.e. set force=true or just starting with \"force\""); + detailLine(sb,indent," (note force is unset after first use)"); + sb.append('\n'); + detailLine(sb,indent,"If \"set force=move\" is set, credentials are deleted, but "); + detailLine(sb,indent,"Permissions and Roles are assigned to the Parent Namespace instead of"); + detailLine(sb,indent,"being deleted. Similarly, Namespaces can be created even though there"); + detailLine(sb,indent,"are Roles/Perms whose type starts with the requested sub-namespace."); + detailLine(sb,indent,"They are simply reassigned to the Child Namespace"); + indent-=4; + api(sb,indent,HttpMethods.DELETE,"authz/ns/[?force=true]",Void.class,true); + } + +} diff --git a/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/ns/Describe.java b/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/ns/Describe.java new file mode 100644 index 00000000..af40ff99 --- /dev/null +++ b/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/ns/Describe.java @@ -0,0 +1,94 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.cmd.ns; + +import org.onap.aaf.auth.cmd.AAFcli; +import org.onap.aaf.auth.cmd.Cmd; +import org.onap.aaf.auth.cmd.Param; +import org.onap.aaf.auth.rserv.HttpMethods; +import org.onap.aaf.cadi.CadiException; +import org.onap.aaf.cadi.LocatorException; +import org.onap.aaf.cadi.client.Future; +import org.onap.aaf.cadi.client.Rcli; +import org.onap.aaf.cadi.client.Retryable; +import org.onap.aaf.misc.env.APIException; + +import aaf.v2_0.NsRequest; + +public class Describe extends Cmd { + private static final String NS_PATH = "/authz/ns"; + public Describe(NS parent) { + super(parent,"describe", + new Param("ns-name",true), + new Param("description",true)); + } + + @Override + public int _exec(final int index, final String ... args) throws CadiException, APIException, LocatorException { + return same(new Retryable() { + @Override + public Integer code(Rcli client) throws CadiException, APIException { + int idx = index; + String name = args[idx++]; + StringBuilder desc = new StringBuilder(); + while (idx < args.length) { + desc.append(args[idx++] + ' '); + } + + NsRequest nsr = new NsRequest(); + nsr.setName(name); + nsr.setDescription(desc.toString()); + + // Set Start/End commands + setStartEnd(nsr); + + Future fn = null; + int rv; + + fn = client.update( + NS_PATH, + getDF(NsRequest.class), + nsr + ); + + if(fn.get(AAFcli.timeout())) { + rv=fn.code(); + pw().println("Description added to Namespace"); + } else { + if((rv=fn.code())==202) { + pw().print("Adding description"); + pw().println(" Accepted, but requires Approvals before actualizing"); + } else { + error(fn); + } + } + return rv; + } + }); + } + + @Override + public void detailedHelp(int indent, StringBuilder sb) { + detailLine(sb,indent,"Add a description to a namespace"); + api(sb,indent,HttpMethods.PUT,"authz/ns",NsRequest.class,true); + } +} \ No newline at end of file diff --git a/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/ns/List.java b/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/ns/List.java new file mode 100644 index 00000000..387bae00 --- /dev/null +++ b/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/ns/List.java @@ -0,0 +1,176 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.cmd.ns; + +import java.util.Collections; +import java.util.Comparator; + +import org.onap.aaf.auth.cmd.BaseCmd; +import org.onap.aaf.auth.cmd.DeprecatedCMD; +import org.onap.aaf.cadi.client.Future; +import org.onap.aaf.misc.env.util.Chrono; + +import aaf.v2_0.Nss; +import aaf.v2_0.Nss.Ns; +import aaf.v2_0.Perms; +import aaf.v2_0.Roles; +import aaf.v2_0.Users; +import aaf.v2_0.Users.User; + +public class List extends BaseCmd { + + public List(NS parent) { + super(parent,"list"); + cmds.add(new ListByName(this)); + +// TODO: uncomment when on cassandra 2.1.2 if we like cli command to get all ns's +// a user is admin or responsible for + cmds.add(new ListAdminResponsible(this)); + cmds.add(new DeprecatedCMD(this,"responsible","'responsible' is deprecated. use 'owner'")); // deprecated + cmds.add(new ListActivity(this)); + cmds.add(new ListUsers(this)); + cmds.add(new ListChildren(this)); + cmds.add(new ListNsKeysByAttrib(this)); + } + + private static final String sformat = " %-72s\n"; + protected static final String kformat = " %-72s\n"; + + + public void report(Future fp, String ... str) { + reportHead(str); + if(fp==null) { + pw().println(" *** Namespace Not Found ***"); + } + + if(fp!=null && fp.value!=null) { + for(Ns ns : fp.value.getNs()) { + pw().println(ns.getName()); + if (this.aafcli.isDetailed()) { + pw().println(" Description"); + pw().format(sformat,ns.getDescription()==null?"":ns.getDescription()); + } + if(ns.getAdmin().size()>0) { + pw().println(" Administrators"); + for(String admin : ns.getAdmin()) { + pw().format(sformat,admin); + } + } + if(ns.getResponsible().size()>0) { + pw().println(" Owners (Responsible for Namespace)"); + for(String responsible : ns.getResponsible()) { + pw().format(sformat,responsible); + } + } + if(ns.getAttrib().size()>0) { + pw().println(" Namespace Attributes"); + for( Ns.Attrib attr : ns.getAttrib()) { + StringBuilder sb = new StringBuilder(attr.getKey()); + if(attr.getValue()==null || attr.getValue().length()>0) { + sb.append('='); + sb.append(attr.getValue()); + } + pw().format(sformat,sb.toString()); + } + + } + } + } + } + + public void reportName(Future fp, String ... str) { + reportHead(str); + if(fp!=null && fp.value!=null) { + java.util.List nss = fp.value.getNs(); + Collections.sort(nss, new Comparator() { + @Override + public int compare(Ns ns1, Ns ns2) { + return ns1.getName().compareTo(ns2.getName()); + } + }); + + for(Ns ns : nss) { + pw().println(ns.getName()); + if (this.aafcli.isDetailed() && ns.getDescription() != null) { + pw().println(" " + ns.getDescription()); + } + } + } + } + + public void reportRole(Future fr) { + if(fr!=null && fr.value!=null && fr.value.getRole().size()>0) { + pw().println(" Roles"); + for(aaf.v2_0.Role r : fr.value.getRole()) { + pw().format(sformat,r.getName()); + } + } + } + + private static final String pformat = " %-30s %-24s %-15s\n"; + public void reportPerm(Future fp) { + if(fp!=null && fp.value!=null && fp.value.getPerm().size()>0) { + pw().println(" Permissions"); + for(aaf.v2_0.Perm p : fp.value.getPerm()) { + pw().format(pformat,p.getType(),p.getInstance(),p.getAction()); + } + } + } + + + private static final String cformat = " %-30s %-6s %-24s\n"; + public void reportCred(Future fc) { + if(fc!=null && fc.value!=null && fc.value.getUser().size()>0) { + pw().println(" Credentials"); + java.util.List users = fc.value.getUser(); + Collections.sort(users, new Comparator() { + @Override + public int compare(User u1, User u2) { + return u1.getId().compareTo(u2.getId()); + } + }); + for(aaf.v2_0.Users.User u : users) { + if (this.aafcli.isTest()) { + pw().format(sformat,u.getId()); + } else { + pw().format(cformat,u.getId(),getType(u),Chrono.niceDateStamp(u.getExpires())); + } + } + } + } + + public static String getType(User u) { + Integer type; + if((type=u.getType())==null) { + type = 9999; + } + switch(type) { + case 1: return "U/P"; + case 2: return "U/P2"; + case 10: return "Cert"; + case 200: return "x509"; + default: + return "n/a"; + } + } + +} diff --git a/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/ns/ListActivity.java b/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/ns/ListActivity.java new file mode 100644 index 00000000..4cc4236e --- /dev/null +++ b/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/ns/ListActivity.java @@ -0,0 +1,80 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.cmd.ns; + +import org.onap.aaf.auth.cmd.AAFcli; +import org.onap.aaf.auth.cmd.Cmd; +import org.onap.aaf.auth.cmd.Param; +import org.onap.aaf.auth.rserv.HttpMethods; +import org.onap.aaf.cadi.CadiException; +import org.onap.aaf.cadi.LocatorException; +import org.onap.aaf.cadi.client.Future; +import org.onap.aaf.cadi.client.Rcli; +import org.onap.aaf.cadi.client.Retryable; +import org.onap.aaf.misc.env.APIException; + +import aaf.v2_0.History; + +/** + * * @author Jonathan + * + */ +public class ListActivity extends Cmd { + private static final String HEADER = "List Activity of Namespace"; + + public ListActivity(List parent) { + super(parent,"activity", + new Param("ns-name",true)); + } + + @Override + public int _exec(int _idx, final String ... args) throws CadiException, APIException, LocatorException { + int idx = _idx; + final String ns = args[idx++]; + + return same(new Retryable() { + @Override + public Integer code(Rcli client) throws CadiException, APIException { + Future fp = client.read( + "/authz/hist/ns/"+ns, + getDF(History.class) + ); + + if(fp.get(AAFcli.timeout())) { + activity(fp.value, HEADER + " [ " + ns + " ]"); + } else { + error(fp); + } + return fp.code(); + } + }); + } + + @Override + public void detailedHelp(int indent, StringBuilder sb) { + detailLine(sb,indent,HEADER); + api(sb,indent,HttpMethods.GET,"authz/hist/ns/",History.class,true); + } + + + +} diff --git a/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/ns/ListAdminResponsible.java b/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/ns/ListAdminResponsible.java new file mode 100644 index 00000000..e17436a2 --- /dev/null +++ b/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/ns/ListAdminResponsible.java @@ -0,0 +1,77 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.cmd.ns; + +import org.onap.aaf.auth.cmd.AAFcli; +import org.onap.aaf.auth.cmd.Cmd; +import org.onap.aaf.auth.cmd.Param; +import org.onap.aaf.auth.rserv.HttpMethods; +import org.onap.aaf.cadi.CadiException; +import org.onap.aaf.cadi.LocatorException; +import org.onap.aaf.cadi.client.Future; +import org.onap.aaf.cadi.client.Rcli; +import org.onap.aaf.cadi.client.Retryable; +import org.onap.aaf.misc.env.APIException; + +import aaf.v2_0.Nss; + +public class ListAdminResponsible extends Cmd { + private static final String HEADER="List Namespaces with "; + private final static String[] options = {"admin","owner"}; + + public ListAdminResponsible(List parent) { + super(parent,null, + new Param(optionsToString(options),true), + new Param("user",true)); + } + + @Override + protected int _exec(final int index, final String... args) throws CadiException, APIException, LocatorException { + + return same(new Retryable() { + @Override + public Integer code(Rcli client) throws CadiException, APIException { + int idx = index; + String title = args[idx++]; + String user = fullID(args[idx++]); + String apipart = "owner".equals(title)?"responsible":title; + + Future fn = client.read("/authz/nss/"+apipart+"/"+user,getDF(Nss.class)); + if(fn.get(AAFcli.timeout())) { + ((List)parent).reportName(fn,HEADER + title + " privileges for ",user); + } else if(fn.code()==404) { + ((List)parent).report(null,HEADER + title + " privileges for ",user); + return 200; + } else { + error(fn); + } + return fn.code(); + } + }); + } + + @Override + public void detailedHelp(int indent, StringBuilder sb) { + detailLine(sb,indent,HEADER + "admin or owner privileges for user"); + api(sb,indent,HttpMethods.GET,"authz/nss//",Nss.class,true); + } +} diff --git a/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/ns/ListByName.java b/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/ns/ListByName.java new file mode 100644 index 00000000..ffc1af89 --- /dev/null +++ b/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/ns/ListByName.java @@ -0,0 +1,105 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.cmd.ns; + +import org.onap.aaf.auth.cmd.AAFcli; +import org.onap.aaf.auth.cmd.Cmd; +import org.onap.aaf.auth.cmd.Param; +import org.onap.aaf.auth.rserv.HttpMethods; +import org.onap.aaf.cadi.CadiException; +import org.onap.aaf.cadi.LocatorException; +import org.onap.aaf.cadi.client.Future; +import org.onap.aaf.cadi.client.Rcli; +import org.onap.aaf.cadi.client.Retryable; +import org.onap.aaf.misc.env.APIException; + +import aaf.v2_0.Nss; +import aaf.v2_0.Nss.Ns; +import aaf.v2_0.Perms; +import aaf.v2_0.Roles; +import aaf.v2_0.Users; + +/** + * p + * @author Jonathan + * + */ +public class ListByName extends Cmd { + private static final String HEADER="List Namespaces by Name"; + + public ListByName(List parent) { + super(parent,"name", + new Param("ns-name",true)); + } + + @Override + public int _exec(int _idx, final String ... args) throws CadiException, APIException, LocatorException { + int idx = _idx; + final String ns=args[idx++]; + return same(new Retryable() { + @Override + public Integer code(Rcli client) throws CadiException, APIException { + Future fn = client.read("/authz/nss/"+ns,getDF(Nss.class)); + if(fn.get(AAFcli.timeout())) { + ((List)parent).report(fn,HEADER,ns); + if(fn.value!=null) { + for(Ns n : fn.value.getNs()) { + Future fr = client.read("/authz/roles/ns/"+n.getName(), getDF(Roles.class)); + if(fr.get(AAFcli.timeout())) { + ((List)parent).reportRole(fr); + } + } + for(Ns n : fn.value.getNs()) { + Future fp = client.read("/authz/perms/ns/"+n.getName()+(aafcli.isDetailed()?"?ns":""), getDF(Perms.class)); + if(fp.get(AAFcli.timeout())) { + ((List)parent).reportPerm(fp); + } + } + for(Ns n : fn.value.getNs()) { + Future fu = client.read("/authn/creds/ns/"+n.getName()+(aafcli.isDetailed()?"?ns":""), getDF(Users.class)); + if(fu.get(AAFcli.timeout())) { + ((List)parent).reportCred(fu); + } + } + } + } else if(fn.code()==404) { + ((List)parent).report(null,HEADER,ns); + return 200; + } else { + error(fn); + } + return fn.code(); + } + }); + } + + @Override + public void detailedHelp(int indent, StringBuilder sb) { + detailLine(sb,indent,HEADER); + api(sb,indent,HttpMethods.GET,"authz/nss/",Nss.class,true); + detailLine(sb,indent,"Indirectly uses:"); + api(sb,indent,HttpMethods.GET,"authz/roles/ns/",Roles.class,false); + api(sb,indent,HttpMethods.GET,"authz/perms/ns/",Perms.class,false); + api(sb,indent,HttpMethods.GET,"authn/creds/ns/",Users.class,false); + } + +} diff --git a/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/ns/ListChildren.java b/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/ns/ListChildren.java new file mode 100644 index 00000000..07dcf701 --- /dev/null +++ b/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/ns/ListChildren.java @@ -0,0 +1,81 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.cmd.ns; + +import org.onap.aaf.auth.cmd.AAFcli; +import org.onap.aaf.auth.cmd.Cmd; +import org.onap.aaf.auth.cmd.Param; +import org.onap.aaf.auth.rserv.HttpMethods; +import org.onap.aaf.cadi.CadiException; +import org.onap.aaf.cadi.LocatorException; +import org.onap.aaf.cadi.client.Future; +import org.onap.aaf.cadi.client.Rcli; +import org.onap.aaf.cadi.client.Retryable; +import org.onap.aaf.misc.env.APIException; + +import aaf.v2_0.Nss; +import aaf.v2_0.Nss.Ns; + +/** + * p + * @author Jonathan + * + */ +public class ListChildren extends Cmd { + private static final String HEADER="List Child Namespaces"; + + public ListChildren(List parent) { + super(parent,"children", + new Param("ns-name",true)); + } + + @Override + public int _exec(int _idx, final String ... args) throws CadiException, APIException, LocatorException { + int idx = _idx; + final String ns=args[idx++]; + return same(new Retryable() { + @Override + public Integer code(Rcli client) throws CadiException, APIException { + Future fn = client.read("/authz/nss/children/"+ns,getDF(Nss.class)); + if(fn.get(AAFcli.timeout())) { + parent.reportHead(HEADER); + for(Ns ns : fn.value.getNs()) { + pw().format(List.kformat, ns.getName()); + } + } else if(fn.code()==404) { + ((List)parent).report(null,HEADER,ns); + return 200; + } else { + error(fn); + } + return fn.code(); + } + }); + } + + @Override + public void detailedHelp(int indent, StringBuilder sb) { + detailLine(sb,indent,HEADER); + api(sb,indent,HttpMethods.GET,"authz/nss/children/",Nss.class,true); + } + +} diff --git a/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/ns/ListNsKeysByAttrib.java b/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/ns/ListNsKeysByAttrib.java new file mode 100644 index 00000000..7c449565 --- /dev/null +++ b/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/ns/ListNsKeysByAttrib.java @@ -0,0 +1,88 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.cmd.ns; + +import org.onap.aaf.auth.cmd.AAFcli; +import org.onap.aaf.auth.cmd.Cmd; +import org.onap.aaf.auth.cmd.Param; +import org.onap.aaf.auth.rserv.HttpMethods; +import org.onap.aaf.cadi.CadiException; +import org.onap.aaf.cadi.LocatorException; +import org.onap.aaf.cadi.client.Future; +import org.onap.aaf.cadi.client.Rcli; +import org.onap.aaf.cadi.client.Retryable; +import org.onap.aaf.misc.env.APIException; + +import aaf.v2_0.Keys; +import aaf.v2_0.Nss; +import aaf.v2_0.Perms; +import aaf.v2_0.Roles; +import aaf.v2_0.Users; + +/** + * p + * @author Jonathan + * + */ +public class ListNsKeysByAttrib extends Cmd { + private static final String HEADER="List Namespace Names by Attribute"; + + public ListNsKeysByAttrib(List parent) { + super(parent,"keys", + new Param("attrib",true)); + } + + @Override + public int _exec(final int idx, final String ... args) throws CadiException, APIException, LocatorException { + final String attrib=args[idx]; + return same(new Retryable() { + @Override + public Integer code(Rcli client) throws CadiException, APIException { + Future fn = client.read("/authz/ns/attrib/"+attrib,getDF(Keys.class)); + if(fn.get(AAFcli.timeout())) { + parent.reportHead(HEADER); + for(String key : fn.value.getKey()) { + pw().printf(List.kformat, key); + } + } else if(fn.code()==404) { + parent.reportHead(HEADER); + pw().println(" *** No Namespaces Found ***"); + return 200; + } else { + error(fn); + } + return fn.code(); + } + }); + } + + @Override + public void detailedHelp(int indent, StringBuilder sb) { + detailLine(sb,indent,HEADER); + api(sb,indent,HttpMethods.GET,"authz/nss/",Nss.class,true); + detailLine(sb,indent,"Indirectly uses:"); + api(sb,indent,HttpMethods.GET,"authz/roles/ns/",Roles.class,false); + api(sb,indent,HttpMethods.GET,"authz/perms/ns/",Perms.class,false); + api(sb,indent,HttpMethods.GET,"authn/creds/ns/",Users.class,false); + } + +} diff --git a/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/ns/ListUsers.java b/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/ns/ListUsers.java new file mode 100644 index 00000000..7106ba6d --- /dev/null +++ b/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/ns/ListUsers.java @@ -0,0 +1,76 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.cmd.ns; + +import javax.xml.datatype.XMLGregorianCalendar; + +import org.onap.aaf.auth.cmd.BaseCmd; +import org.onap.aaf.cadi.CadiException; +import org.onap.aaf.cadi.client.Future; + +import aaf.v2_0.Nss; +import aaf.v2_0.Users.User; + +public class ListUsers extends BaseCmd { + + public ListUsers(List parent) { + super(parent,"user"); + cmds.add(new ListUsersWithPerm(this)); + cmds.add(new ListUsersInRole(this)); + } + private static final Future dummy = new Future(){ + + @Override + public boolean get(int timeout) throws CadiException { + return false; + } + + @Override + public int code() { + return 0; + } + + @Override + public String body() { + return null; + } + + @Override + public String header(String tag) { + return null; + } + }; + public void report(String header, String ns) { + ((List)parent).report(dummy, header,ns); + } + + public void report(String subHead) { + pw().println(subHead); + } + + private static final String uformat = "%s%-50s expires:%02d/%02d/%04d\n"; + public void report(String prefix, User u) { + XMLGregorianCalendar xgc = u.getExpires(); + pw().format(uformat,prefix,u.getId(),xgc.getMonth()+1,xgc.getDay(),xgc.getYear()); + } + +} diff --git a/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/ns/ListUsersContact.java b/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/ns/ListUsersContact.java new file mode 100644 index 00000000..1c988e30 --- /dev/null +++ b/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/ns/ListUsersContact.java @@ -0,0 +1,128 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.cmd.ns; + +import java.util.HashSet; +import java.util.Set; + +import org.onap.aaf.auth.cmd.AAFcli; +import org.onap.aaf.auth.cmd.Cmd; +import org.onap.aaf.auth.cmd.Param; +import org.onap.aaf.auth.rserv.HttpMethods; +import org.onap.aaf.cadi.CadiException; +import org.onap.aaf.cadi.LocatorException; +import org.onap.aaf.cadi.client.Future; +import org.onap.aaf.cadi.client.Rcli; +import org.onap.aaf.cadi.client.Retryable; +import org.onap.aaf.misc.env.APIException; + +import aaf.v2_0.Nss; +import aaf.v2_0.Nss.Ns; +import aaf.v2_0.Role; +import aaf.v2_0.Roles; +import aaf.v2_0.Users; +import aaf.v2_0.Users.User; + +/** + * p + * @author Jonathan + * + */ +public class ListUsersContact extends Cmd { + private static final String HEADER="List Contacts of Namespace "; + + public ListUsersContact(ListUsers parent) { + super(parent,"contact", + new Param("ns-name",true)); + } + + @Override + public int _exec(int _idx, final String ... args) throws CadiException, APIException, LocatorException { + int idx = _idx; + final String ns=args[idx++]; + final boolean detail = aafcli.isDetailed(); + return same(new Retryable() { + @Override + public Integer code(Rcli client) throws CadiException, APIException { + ((ListUsers)parent).report(HEADER,ns); + Future fn = client.read("/authz/nss/"+ns,getDF(Nss.class)); + if(fn.get(AAFcli.timeout())) { + if(fn.value!=null) { + Set uset = detail?null:new HashSet(); + for(Ns n : fn.value.getNs()) { + Future fr = client.read("/authz/roles/ns/"+n.getName(), getDF(Roles.class)); + if(fr.get(AAFcli.timeout())) { + for(Role r : fr.value.getRole()) { + if(detail) { + ((ListUsers)parent).report(r.getName()); + } + Future fus = client.read( + "/authz/users/role/"+r.getName(), + getDF(Users.class) + ); + if(fus.get(AAFcli.timeout())) { + for(User u : fus.value.getUser()) { + if(detail) { + ((ListUsers)parent).report(" ",u); + } else { + uset.add(u.getId()); + } + } + } else if(fn.code()==404) { + return 200; + } + } + } + } + if(uset!=null) { + for(String u : uset) { + pw().print(" "); + pw().println(u); + } + } + } + } else if(fn.code()==404) { + return 200; + } else { + error(fn); + } + return fn.code(); + } + }); + } + + @Override + public void detailedHelp(int _indent, StringBuilder sb) { + int indent = _indent; + detailLine(sb,indent,HEADER); + indent+=4; + detailLine(sb,indent,"Report Users associated with this Namespace's Roles"); + sb.append('\n'); + detailLine(sb,indent,"If \"set details=true\" is specified, then all roles are printed "); + detailLine(sb,indent,"with the associated users and expiration dates"); + indent-=4; + api(sb,indent,HttpMethods.GET,"authz/nss/",Nss.class,true); + api(sb,indent,HttpMethods.GET,"authz/roles/ns/",Roles.class,false); + api(sb,indent,HttpMethods.GET,"authz/users/role/",Users.class,false); + } + +} diff --git a/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/ns/ListUsersInRole.java b/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/ns/ListUsersInRole.java new file mode 100644 index 00000000..2ee8bd2c --- /dev/null +++ b/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/ns/ListUsersInRole.java @@ -0,0 +1,128 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.cmd.ns; + +import java.util.HashSet; +import java.util.Set; + +import org.onap.aaf.auth.cmd.AAFcli; +import org.onap.aaf.auth.cmd.Cmd; +import org.onap.aaf.auth.cmd.Param; +import org.onap.aaf.auth.rserv.HttpMethods; +import org.onap.aaf.cadi.CadiException; +import org.onap.aaf.cadi.LocatorException; +import org.onap.aaf.cadi.client.Future; +import org.onap.aaf.cadi.client.Rcli; +import org.onap.aaf.cadi.client.Retryable; +import org.onap.aaf.misc.env.APIException; + +import aaf.v2_0.Nss; +import aaf.v2_0.Nss.Ns; +import aaf.v2_0.Role; +import aaf.v2_0.Roles; +import aaf.v2_0.Users; +import aaf.v2_0.Users.User; + +/** + * p + * @author Jonathan + * + */ +public class ListUsersInRole extends Cmd { + private static final String HEADER="List Users in Roles of Namespace "; + + public ListUsersInRole(ListUsers parent) { + super(parent,"role", + new Param("ns-name",true)); + } + + @Override + public int _exec(int _idx, final String ... args) throws CadiException, APIException, LocatorException { + int idx = _idx; + final String ns=args[idx++]; + final boolean detail = aafcli.isDetailed(); + return same(new Retryable() { + @Override + public Integer code(Rcli client) throws CadiException, APIException { + ((ListUsers)parent).report(HEADER,ns); + Future fn = client.read("/authz/nss/"+ns,getDF(Nss.class)); + if(fn.get(AAFcli.timeout())) { + if(fn.value!=null) { + Set uset = detail?null:new HashSet(); + for(Ns n : fn.value.getNs()) { + Future fr = client.read("/authz/roles/ns/"+n.getName(), getDF(Roles.class)); + if(fr.get(AAFcli.timeout())) { + for(Role r : fr.value.getRole()) { + if(detail) { + ((ListUsers)parent).report(r.getName()); + } + Future fus = client.read( + "/authz/users/role/"+r.getName(), + getDF(Users.class) + ); + if(fus.get(AAFcli.timeout())) { + for(User u : fus.value.getUser()) { + if(detail) { + ((ListUsers)parent).report(" ",u); + } else { + uset.add(u.getId()); + } + } + } else if(fn.code()==404) { + return 200; + } + } + } + } + if(uset!=null) { + for(String u : uset) { + pw().print(" "); + pw().println(u); + } + } + } + } else if(fn.code()==404) { + return 200; + } else { + error(fn); + } + return fn.code(); + } + }); + } + + @Override + public void detailedHelp(int _indent, StringBuilder sb) { + int indent = _indent; + detailLine(sb,indent,HEADER); + indent+=4; + detailLine(sb,indent,"Report Users associated with this Namespace's Roles"); + sb.append('\n'); + detailLine(sb,indent,"If \"set details=true\" is specified, then all roles are printed "); + detailLine(sb,indent,"with the associated users and expiration dates"); + indent-=4; + api(sb,indent,HttpMethods.GET,"authz/nss/",Nss.class,true); + api(sb,indent,HttpMethods.GET,"authz/roles/ns/",Roles.class,false); + api(sb,indent,HttpMethods.GET,"authz/users/role/",Users.class,false); + } + +} diff --git a/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/ns/ListUsersWithPerm.java b/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/ns/ListUsersWithPerm.java new file mode 100644 index 00000000..97ccf569 --- /dev/null +++ b/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/ns/ListUsersWithPerm.java @@ -0,0 +1,128 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.cmd.ns; + +import java.util.HashSet; +import java.util.Set; + +import org.onap.aaf.auth.cmd.AAFcli; +import org.onap.aaf.auth.cmd.Cmd; +import org.onap.aaf.auth.cmd.Param; +import org.onap.aaf.auth.rserv.HttpMethods; +import org.onap.aaf.cadi.CadiException; +import org.onap.aaf.cadi.LocatorException; +import org.onap.aaf.cadi.client.Future; +import org.onap.aaf.cadi.client.Rcli; +import org.onap.aaf.cadi.client.Retryable; +import org.onap.aaf.misc.env.APIException; + +import aaf.v2_0.Nss; +import aaf.v2_0.Nss.Ns; +import aaf.v2_0.Perm; +import aaf.v2_0.Perms; +import aaf.v2_0.Users; +import aaf.v2_0.Users.User; + +/** + * p + * @author Jonathan + * + */ +public class ListUsersWithPerm extends Cmd { + private static final String HEADER="List Users of Permissions of Namespace "; + + public ListUsersWithPerm(ListUsers parent) { + super(parent,"perm", + new Param("ns-name",true)); + } + + @Override + public int _exec(int _idx, final String ... args) throws CadiException, APIException, LocatorException { + int idx = _idx; + final String ns=args[idx++]; + final boolean detail = aafcli.isDetailed(); + return same(new Retryable() { + @Override + public Integer code(Rcli client) throws CadiException, APIException { + ((ListUsers)parent).report(HEADER,ns); + Future fn = client.read("/authz/nss/"+ns,getDF(Nss.class)); + if(fn.get(AAFcli.timeout())) { + if(fn.value!=null) { + Set uset = detail?null:new HashSet(); + + for(Ns n : fn.value.getNs()) { + Future fp = client.read("/authz/perms/ns/"+n.getName()+(aafcli.isDetailed()?"?ns":"") + , getDF(Perms.class)); + if(fp.get(AAFcli.timeout())) { + for(Perm p : fp.value.getPerm()) { + String perm = p.getType()+'/'+p.getInstance()+'/'+p.getAction(); + if(detail)((ListUsers)parent).report(perm); + Future fus = client.read( + "/authz/users/perm/"+perm, + getDF(Users.class) + ); + if(fus.get(AAFcli.timeout())) { + for(User u : fus.value.getUser()) { + if(detail) + ((ListUsers)parent).report(" ",u); + else + uset.add(u.getId()); + } + } else if(fn.code()==404) { + return 200; + } + } + } + } + if(uset!=null) { + for(String u : uset) { + pw().print(" "); + pw().println(u); + } + } + } + } else if(fn.code()==404) { + return 200; + } else { + error(fn); + } + return fn.code(); + } + }); + } + + @Override + public void detailedHelp(int _indent, StringBuilder sb) { + int indent = _indent; + detailLine(sb,indent,HEADER); + indent+=4; + detailLine(sb,indent,"Report Users associated with this Namespace's Permissions"); + sb.append('\n'); + detailLine(sb,indent,"If \"set detail=true\" is specified, then Permissions are printed with the associated"); + detailLine(sb,indent,"users and expiration dates"); + indent-=4; + api(sb,indent,HttpMethods.GET,"authz/nss/",Nss.class,true); + api(sb,indent,HttpMethods.GET,"authz/perms/ns/",Perms.class,false); + api(sb,indent,HttpMethods.GET,"authz/users/perm///",Users.class,false); + } + +} diff --git a/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/ns/NS.java b/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/ns/NS.java new file mode 100644 index 00000000..8ceffde7 --- /dev/null +++ b/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/ns/NS.java @@ -0,0 +1,45 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.cmd.ns; + +import org.onap.aaf.auth.cmd.AAFcli; +import org.onap.aaf.auth.cmd.BaseCmd; +import org.onap.aaf.auth.cmd.DeprecatedCMD; +import org.onap.aaf.misc.env.APIException; + +public class NS extends BaseCmd { +// final Role role; + + public NS(AAFcli aafcli) throws APIException { + super(aafcli, "ns"); +// this.role = role; + + cmds.add(new Create(this)); + cmds.add(new Delete(this)); + cmds.add(new Admin(this)); + cmds.add(new Owner(this)); + cmds.add(new DeprecatedCMD(this,"responsible","'responsible' is deprecated. use 'owner'")); // deprecated + cmds.add(new Describe(this)); + cmds.add(new Attrib(this)); + cmds.add(new List(this)); + } +} diff --git a/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/ns/Owner.java b/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/ns/Owner.java new file mode 100644 index 00000000..5d1df496 --- /dev/null +++ b/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/ns/Owner.java @@ -0,0 +1,109 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.cmd.ns; + +import org.onap.aaf.auth.cmd.AAFcli; +import org.onap.aaf.auth.cmd.BaseCmd; +import org.onap.aaf.auth.cmd.Param; +import org.onap.aaf.auth.rserv.HttpMethods; +import org.onap.aaf.cadi.CadiException; +import org.onap.aaf.cadi.LocatorException; +import org.onap.aaf.cadi.client.Future; +import org.onap.aaf.cadi.client.Rcli; +import org.onap.aaf.cadi.client.Retryable; +import org.onap.aaf.misc.env.APIException; + +public class Owner extends BaseCmd { + private final static String[] options = {"add","del"}; + + public Owner(NS ns) throws APIException { + super(ns,"owner", + new Param(optionsToString(options),true), + new Param("ns-name",true), + new Param("id[,id]*",true) + ); + } + + @Override + public int _exec(int _idx, final String ... args) throws CadiException, APIException, LocatorException { + int idx = _idx; + + final int option = whichOption(options, args[idx++]); + final String ns = args[idx++]; + final String ids[] = args[idx++].split(","); + + return same(new Retryable() { + @Override + public Integer code(Rcli client) throws CadiException, APIException { + Future fp=null; + for(String id : ids) { + id=fullID(id); + String verb; + switch(option) { + case 0: + fp = client.create("/authz/ns/"+ns+"/responsible/"+id,Void.class); + verb = " is now "; + break; + case 1: + fp = client.delete("/authz/ns/"+ns+"/responsible/"+id,Void.class); + verb = " is no longer "; + break; + default: + throw new CadiException("Bad Argument"); + }; + + if(fp.get(AAFcli.timeout())) { + pw().append(id); + pw().append(verb); + pw().append("responsible for "); + pw().println(ns); + } else { + error(fp); + return fp.code(); + } + } + return fp==null?500:fp.code(); + } + }); + } + + @Override + public void detailedHelp(int _indent, StringBuilder sb) { + int indent = _indent; + detailLine(sb,indent,"Add or Delete Responsible person to/from Namespace"); + indent+=2; + detailLine(sb,indent,"Namespace Owners are responsible to receive Notifications and "); + detailLine(sb,indent,"approve Requests regarding this Namespace. Companies have "); + detailLine(sb,indent,"Policies as to who may take on this responsibility"); + + indent+=2; + detailLine(sb,indent,"name - Name of Namespace"); + detailLine(sb,indent,"id - Credential of Person(s) to be made responsible"); + sb.append('\n'); + detailLine(sb,indent,"aafcli will call API on each ID presented."); + indent-=4; + api(sb,indent,HttpMethods.POST,"authz/ns//responsible/",Void.class,true); + api(sb,indent,HttpMethods.DELETE,"authz/ns//responsible/",Void.class,false); + } + + +} diff --git a/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/perm/Create.java b/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/perm/Create.java new file mode 100644 index 00000000..cc674568 --- /dev/null +++ b/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/perm/Create.java @@ -0,0 +1,163 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.cmd.perm; + +import org.onap.aaf.auth.cmd.AAFcli; +import org.onap.aaf.auth.cmd.Cmd; +import org.onap.aaf.auth.cmd.Param; +import org.onap.aaf.auth.rserv.HttpMethods; +import org.onap.aaf.cadi.CadiException; +import org.onap.aaf.cadi.LocatorException; +import org.onap.aaf.cadi.client.Future; +import org.onap.aaf.cadi.client.Rcli; +import org.onap.aaf.cadi.client.Retryable; +import org.onap.aaf.misc.env.APIException; + +import aaf.v2_0.PermRequest; +import aaf.v2_0.RoleRequest; + +/** + * + * @author Jonathan + * + */ +public class Create extends Cmd { + public Create(Perm parent) { + super(parent,"create", + new Param("type",true), + new Param("instance",true), + new Param("action", true), + new Param("role[,role]* (to Grant to)", false) + ); + } + + @Override + public int _exec(final int index, final String ... args) throws CadiException, APIException, LocatorException { + return same(new Retryable() { + @Override + public Integer code(Rcli client) throws CadiException, APIException { + int idx = index; + final PermRequest pr = new PermRequest(); + pr.setType(args[idx++]); + pr.setInstance(args[idx++]); + pr.setAction(args[idx++]); + String roleCommas = (args.length>idx)?args[idx++]:null; + String[] roles = roleCommas==null?null:roleCommas.split("\\s*,\\s*"); + boolean force = aafcli.forceString()!=null; + int rv; + + if(roles!=null && force) { // Make sure Roles are Created + RoleRequest rr = new RoleRequest(); + for(String role : roles) { + rr.setName(role);; + Future fr = client.create( + "/authz/role", + getDF(RoleRequest.class), + rr + ); + fr.get(AAFcli.timeout()); + switch(fr.code()){ + case 201: + pw().println("Created Role [" + role + ']'); + break; + case 409: + break; + default: + pw().println("Role [" + role + "] does not exist, and cannot be created."); + return 206 /*HttpStatus.PARTIAL_CONTENT_206*/; + } + } + } + + // Set Start/End commands + setStartEnd(pr); + setQueryParamsOn(client); + Future fp = client.create( + "/authz/perm", + getDF(PermRequest.class), + pr + ); + if(fp.get(AAFcli.timeout())) { + rv = fp.code(); + pw().println("Created Permission"); + if(roles!=null) { + if(aafcli.forceString()!=null) { // Make sure Roles are Created + RoleRequest rr = new RoleRequest(); + for(String role : roles) { + rr.setName(role);; + Future fr = client.create( + "/authz/role", + getDF(RoleRequest.class), + rr + ); + fr.get(AAFcli.timeout()); + switch(fr.code()){ + case 201: + case 409:break; + default: + + } + } + } + + try { + if(201!=(rv=((Perm)parent)._exec(0, + new String[] {"grant",pr.getType(),pr.getInstance(),pr.getAction(),roleCommas}))) { + rv = 206 /*HttpStatus.PARTIAL_CONTENT_206*/; + } + } catch (LocatorException e) { + throw new CadiException(e); + } + } + } else { + rv = fp.code(); + if(rv==409 && force) { + rv = 201; + } else if(rv==202) { + pw().println("Permission Creation Accepted, but requires Approvals before actualizing"); + if (roles!=null) + pw().println("You need to grant the roles after approval."); + } else { + error(fp); + } + } + return rv; + } + }); + } + + @Override + public void detailedHelp(int _indent, StringBuilder sb) { + int indent = _indent; + detailLine(sb,indent,"Create a Permission with:"); + detailLine(sb,indent+=2,"type - A Namespace qualified identifier identifying the kind of"); + detailLine(sb,indent+11,"resource to be protected"); + detailLine(sb,indent,"instance - A name that distinguishes a particular instance of resource"); + detailLine(sb,indent,"action - What kind of action is allowed"); + detailLine(sb,indent,"role(s) - Perms granted to these Comma separated Role(s)"); + detailLine(sb,indent+11,"Nonexistent role(s) will be created, if in same namespace"); + sb.append('\n'); + detailLine(sb,indent+2,"Note: Instance and Action can be a an '*' (enter \\\\* on Unix Shell)"); + api(sb,indent,HttpMethods.POST,"authz/perm",PermRequest.class,true); + } + +} diff --git a/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/perm/Delete.java b/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/perm/Delete.java new file mode 100644 index 00000000..ba123d58 --- /dev/null +++ b/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/perm/Delete.java @@ -0,0 +1,89 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.cmd.perm; + +import org.onap.aaf.auth.cmd.AAFcli; +import org.onap.aaf.auth.cmd.Cmd; +import org.onap.aaf.auth.cmd.Param; +import org.onap.aaf.auth.rserv.HttpMethods; +import org.onap.aaf.cadi.CadiException; +import org.onap.aaf.cadi.LocatorException; +import org.onap.aaf.cadi.client.Future; +import org.onap.aaf.cadi.client.Rcli; +import org.onap.aaf.cadi.client.Retryable; +import org.onap.aaf.misc.env.APIException; + +import aaf.v2_0.PermRequest; + +/** + * p + * @author Jonathan + * + */ +public class Delete extends Cmd { + public Delete(Perm parent) { + super(parent,"delete", + new Param("type",true), + new Param("instance",true), + new Param("action", true)); + } + + @Override + public int _exec(final int index, final String ... args) throws CadiException, APIException, LocatorException { + return same(new Retryable() { + @Override + public Integer code(Rcli client) throws CadiException, APIException { + int idx = index; + // Object Style Delete + PermRequest pk = new PermRequest(); + pk.setType(args[idx++]); + pk.setInstance(args[idx++]); + pk.setAction(args[idx++]); + + // Set "Force" if set + setQueryParamsOn(client); + Future fp = client.delete( + "/authz/perm", + getDF(PermRequest.class), + pk); + if(fp.get(AAFcli.timeout())) { + pw().println("Deleted Permission"); + } else { + if(fp.code()==202) { + pw().println("Permission Deletion Accepted, but requires Approvals before actualizing"); + } else { + error(fp); + } + } + return fp.code(); + } + }); + } + + @Override + public void detailedHelp(int indent, StringBuilder sb) { + detailLine(sb,indent,"Delete a Permission with type,instance and action"); + detailLine(sb,indent+4,"see Create for definitions"); + api(sb,indent,HttpMethods.DELETE,"authz/perm",PermRequest.class,true); + } + +} diff --git a/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/perm/Describe.java b/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/perm/Describe.java new file mode 100644 index 00000000..5a3fad3e --- /dev/null +++ b/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/perm/Describe.java @@ -0,0 +1,100 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.cmd.perm; + +import org.onap.aaf.auth.cmd.AAFcli; +import org.onap.aaf.auth.cmd.Cmd; +import org.onap.aaf.auth.cmd.Param; +import org.onap.aaf.auth.rserv.HttpMethods; +import org.onap.aaf.cadi.CadiException; +import org.onap.aaf.cadi.LocatorException; +import org.onap.aaf.cadi.client.Future; +import org.onap.aaf.cadi.client.Rcli; +import org.onap.aaf.cadi.client.Retryable; +import org.onap.aaf.misc.env.APIException; + +import aaf.v2_0.PermRequest; + +public class Describe extends Cmd { + private static final String PERM_PATH = "/authz/perm"; + public Describe(Perm parent) { + super(parent,"describe", + new Param("type",true), + new Param("instance", true), + new Param("action", true), + new Param("description",true)); + } + + @Override + public int _exec(final int index, final String ... args) throws CadiException, APIException, LocatorException { + return same(new Retryable() { + @Override + public Integer code(Rcli client) throws CadiException, APIException { + int idx = index; + String type = args[idx++]; + String instance = args[idx++]; + String action = args[idx++]; + StringBuilder desc = new StringBuilder(); + while (idx < args.length) { + desc.append(args[idx++] + ' '); + } + + PermRequest pr = new PermRequest(); + pr.setType(type); + pr.setInstance(instance); + pr.setAction(action); + pr.setDescription(desc.toString()); + + // Set Start/End commands + setStartEnd(pr); + + Future fp = null; + int rv; + + fp = client.update( + PERM_PATH, + getDF(PermRequest.class), + pr + ); + + if(fp.get(AAFcli.timeout())) { + rv=fp.code(); + pw().println("Description added to Permission"); + } else { + if((rv=fp.code())==202) { + pw().print("Adding description"); + pw().println(" Accepted, but requires Approvals before actualizing"); + } else { + error(fp); + } + } + return rv; + } + }); + } + + @Override + public void detailedHelp(int indent, StringBuilder sb) { + detailLine(sb,indent,"Add a description to a permission"); + api(sb,indent,HttpMethods.PUT,"authz/perm",PermRequest.class,true); + } +} diff --git a/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/perm/Grant.java b/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/perm/Grant.java new file mode 100644 index 00000000..d4b26a84 --- /dev/null +++ b/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/perm/Grant.java @@ -0,0 +1,150 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.cmd.perm; + +import org.onap.aaf.auth.cmd.AAFcli; +import org.onap.aaf.auth.cmd.Cmd; +import org.onap.aaf.auth.cmd.Param; +import org.onap.aaf.auth.rserv.HttpMethods; +import org.onap.aaf.cadi.CadiException; +import org.onap.aaf.cadi.LocatorException; +import org.onap.aaf.cadi.client.Future; +import org.onap.aaf.cadi.client.Rcli; +import org.onap.aaf.cadi.client.Retryable; +import org.onap.aaf.misc.env.APIException; + +import aaf.v2_0.Pkey; +import aaf.v2_0.RolePermRequest; + +/** + * + * @author Jonathan + * + */ +public class Grant extends Cmd { + private final static String[] options = {"grant","ungrant","setTo"}; + + public Grant(Perm parent) { + super(parent,null, + new Param(optionsToString(options),true), + new Param("type",true), + new Param("instance",true), + new Param("action",true), + new Param("role[,role]* (!REQ S)",false) + ); + } + + @Override + public int _exec(final int index, final String ... args) throws CadiException, APIException, LocatorException { + return same(new Retryable() { + @Override + public Integer code(Rcli client) throws CadiException, APIException { + int idx = index; + String action = args[idx++]; + int option = whichOption(options, action); + + RolePermRequest rpr = new RolePermRequest(); + Pkey pk = new Pkey(); + pk.setType(args[idx++]); + pk.setInstance(args[idx++]); + pk.setAction(args[idx++]); + rpr.setPerm(pk); + setStartEnd(rpr); + + Future frpr = null; + + if (option != 2) { + String[] roles = args[idx++].split(","); + String strA,strB; + for(String role : roles) { + rpr.setRole(role); + if(option==0) { + // You can request to Grant Permission to a Role + setQueryParamsOn(client); + frpr = client.create( + "/authz/role/perm", + getDF(RolePermRequest.class), + rpr + ); + strA = "Granted Permission ["; + strB = "] to Role ["; + } else { + // You can request to UnGrant Permission to a Role + setQueryParamsOn(client); + frpr = client.delete( + "/authz/role/" + role + "/perm", + getDF(RolePermRequest.class), + rpr + ); + strA = "UnGranted Permission ["; + strB = "] from Role ["; + } + if(frpr.get(AAFcli.timeout())) { + pw().println(strA + pk.getType() + '|' + pk.getInstance() + '|' + pk.getAction() + + strB + role +']'); + } else { + if (frpr.code()==202) { + pw().print("Permission Role "); + pw().print(option==0?"Granted":"Ungranted"); + pw().println(" Accepted, but requires Approvals before actualizing"); + } else { + error(frpr); + idx=Integer.MAX_VALUE; + } + } + } + } else { + String allRoles = ""; + if (idx < args.length) + allRoles = args[idx++]; + + rpr.setRole(allRoles); + frpr = client.update( + "/authz/role/perm", + getDF(RolePermRequest.class), + rpr); + if(frpr.get(AAFcli.timeout())) { + pw().println("Set Permission's Roles to [" + allRoles + "]"); + } else { + error(frpr); + } + } + return frpr==null?0:frpr.code(); + } + }); + } + + @Override + public void detailedHelp(int indent, StringBuilder sb) { + detailLine(sb,indent,"Grant a Permission to a Role or Roles OR"); + detailLine(sb,indent,"Ungrant a Permission from a Role or Roles OR"); + detailLine(sb,indent,"Set a Permission's roles to roles supplied."); + detailLine(sb,indent+4,"WARNING: Roles supplied with setTo will be the ONLY roles attached to this permission"); + detailLine(sb,indent+8,"If no roles are supplied, permission's roles are reset."); + detailLine(sb,indent,"see Create for definitions of type,instance and action"); + api(sb,indent,HttpMethods.POST,"authz/role/perm",RolePermRequest.class,true); + api(sb,indent,HttpMethods.DELETE,"authz/role//perm",RolePermRequest.class,false); + api(sb,indent,HttpMethods.PUT,"authz/role/perm",RolePermRequest.class,false); + + } + +} diff --git a/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/perm/List.java b/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/perm/List.java new file mode 100644 index 00000000..2eadd38c --- /dev/null +++ b/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/perm/List.java @@ -0,0 +1,116 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.cmd.perm; + +import java.util.Collections; +import java.util.Comparator; + +import org.onap.aaf.auth.cmd.AAFcli; +import org.onap.aaf.auth.cmd.BaseCmd; +import org.onap.aaf.cadi.CadiException; +import org.onap.aaf.cadi.client.Future; +import org.onap.aaf.cadi.client.Retryable; +import org.onap.aaf.misc.env.APIException; + +import aaf.v2_0.Perms; + +public class List extends BaseCmd { +// private static final String LIST_PERM_DETAILS = "list permission details"; + + public List(Perm parent) { + super(parent,"list"); + + cmds.add(new ListByUser(this)); + cmds.add(new ListByName(this)); + cmds.add(new ListByNS(this)); + cmds.add(new ListByRole(this)); + cmds.add(new ListActivity(this)); + } + // Package Level on purpose + abstract class ListPerms extends Retryable { + protected int list(Future fp,String header, String parentPerm) throws CadiException, APIException { + if(fp.get(AAFcli.timeout())) { + report(fp,header, parentPerm); + } else { + error(fp); + } + return fp.code(); + } + } + + private static final Comparator permCompare = new Comparator() { + @Override + public int compare(aaf.v2_0.Perm a, aaf.v2_0.Perm b) { + int rc; + if((rc=a.getType().compareTo(b.getType()))!=0) { + return rc; + } + if((rc=a.getInstance().compareTo(b.getInstance()))!=0) { + return rc; + } + return a.getAction().compareTo(b.getAction()); + } + }; + + private static final String permFormat = "%-30s %-30s %-10s\n"; + + void report(Future fp, String ... str) { + reportHead(str); + if (this.aafcli.isDetailed()) { + String format = "%-36s %-30s %-15s\n"; + String descFmt = " %-75s\n"; + reportColHead(format + descFmt,"[PERM NS].Type","Instance","Action", "Description"); + Collections.sort(fp.value.getPerm(),permCompare); + for(aaf.v2_0.Perm p : fp.value.getPerm()) { + String pns = p.getNs(); + if(pns==null) { + pw().format(format, + p.getType(), + p.getInstance(), + p.getAction()); + } else { + pw().format(format, + '['+pns + "]." + p.getType().substring(pns.length()+1), + p.getInstance(), + p.getAction()); + } + String desc = p.getDescription(); + if(desc!=null && desc.length()>0) { + pw().format(descFmt,p.getDescription()); + } + } + pw().println(); + } else { + String format = reportColHead(permFormat,"PERM Type","Instance","Action"); + + Collections.sort(fp.value.getPerm(),permCompare); + for(aaf.v2_0.Perm p : fp.value.getPerm()) { + pw().format(format, + p.getType(), + p.getInstance(), + p.getAction()); + } + pw().println(); + } + } + +} diff --git a/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/perm/ListActivity.java b/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/perm/ListActivity.java new file mode 100644 index 00000000..4b5f569b --- /dev/null +++ b/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/perm/ListActivity.java @@ -0,0 +1,76 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.cmd.perm; + +import org.onap.aaf.auth.cmd.AAFcli; +import org.onap.aaf.auth.cmd.Cmd; +import org.onap.aaf.auth.cmd.Param; +import org.onap.aaf.auth.rserv.HttpMethods; +import org.onap.aaf.cadi.CadiException; +import org.onap.aaf.cadi.LocatorException; +import org.onap.aaf.cadi.client.Future; +import org.onap.aaf.cadi.client.Rcli; +import org.onap.aaf.cadi.client.Retryable; +import org.onap.aaf.misc.env.APIException; + +import aaf.v2_0.History; + +/** + * * @author Jonathan + * + */ +public class ListActivity extends Cmd { + private static final String HEADER = "List Activity of Permission"; + + public ListActivity(List parent) { + super(parent,"activity", + new Param("type",true)); + } + + @Override + public int _exec(final int index, final String ... args) throws CadiException, APIException, LocatorException { + return same(new Retryable() { + @Override + public Integer code(Rcli client) throws CadiException, APIException { + int idx = index; + String type = args[idx++]; + Future fp = client.read( + "/authz/hist/perm/"+type, + getDF(History.class) + ); + if(fp.get(AAFcli.timeout())) { + activity(fp.value, HEADER + " [ " + type + " ]"); + } else { + error(fp); + } + return fp.code(); + } + }); + } + + @Override + public void detailedHelp(int indent, StringBuilder sb) { + detailLine(sb,indent,HEADER); + api(sb,indent,HttpMethods.GET,"authz/hist/perm/",History.class,true); + } + +} diff --git a/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/perm/ListByNS.java b/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/perm/ListByNS.java new file mode 100644 index 00000000..304055bf --- /dev/null +++ b/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/perm/ListByNS.java @@ -0,0 +1,71 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.cmd.perm; + +import org.onap.aaf.auth.cmd.Cmd; +import org.onap.aaf.auth.cmd.Param; +import org.onap.aaf.auth.rserv.HttpMethods; +import org.onap.aaf.cadi.CadiException; +import org.onap.aaf.cadi.LocatorException; +import org.onap.aaf.cadi.client.Future; +import org.onap.aaf.cadi.client.Rcli; +import org.onap.aaf.misc.env.APIException; + +import aaf.v2_0.Perms; + +/** + * Return Perms by NS + * + * @author Jeremiah + * + */ +public class ListByNS extends Cmd { + private static final String HEADER = "List Perms by NS "; + + public ListByNS(List parent) { + super(parent,"ns", + new Param("name",true)); + } + + public int _exec( int idx, final String ... args) throws CadiException, APIException, LocatorException { + final String ns=args[idx]; + + return same(((List)parent).new ListPerms() { + @Override + public Integer code(Rcli client) throws CadiException, APIException { + Future fp = client.read( + "/authz/perms/ns/"+ns+(aafcli.isDetailed()?"?ns":""), + getDF(Perms.class) + ); + return list(fp, HEADER, ns); + } + }); + } + + @Override + public void detailedHelp(int indent, StringBuilder sb) { + detailLine(sb,indent,HEADER); + api(sb,indent,HttpMethods.GET,"authz/perms/ns/",Perms.class,true); + } + + +} diff --git a/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/perm/ListByName.java b/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/perm/ListByName.java new file mode 100644 index 00000000..6310e24b --- /dev/null +++ b/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/perm/ListByName.java @@ -0,0 +1,69 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.cmd.perm; + +import org.onap.aaf.auth.cmd.Cmd; +import org.onap.aaf.auth.cmd.Param; +import org.onap.aaf.auth.rserv.HttpMethods; +import org.onap.aaf.cadi.CadiException; +import org.onap.aaf.cadi.LocatorException; +import org.onap.aaf.cadi.client.Future; +import org.onap.aaf.cadi.client.Rcli; +import org.onap.aaf.misc.env.APIException; + +import aaf.v2_0.Perms; + +/** + * + * @author Jonathan + * + */ +public class ListByName extends Cmd { + private static final String HEADER = "List Child Permissions"; + + public ListByName(List parent) { + super(parent,"name", + new Param("root perm name",true)); + } + + public int _exec(final int index, final String ... args) throws CadiException, APIException, LocatorException { + return same(((List)parent).new ListPerms() { + @Override + public Integer code(Rcli client) throws CadiException, APIException { + String parentPerm=args[index]; + + Future fp = client.read( + "/authz/perms/"+parentPerm+(aafcli.isDetailed()?"?ns":""), + getDF(Perms.class) + ); + return list(fp,HEADER,parentPerm); + } + }); + } + + @Override + public void detailedHelp(int indent, StringBuilder sb) { + detailLine(sb,indent,HEADER); + api(sb,indent,HttpMethods.GET,"authz/perms/",Perms.class,true); + } + +} diff --git a/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/perm/ListByRole.java b/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/perm/ListByRole.java new file mode 100644 index 00000000..75b88538 --- /dev/null +++ b/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/perm/ListByRole.java @@ -0,0 +1,72 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.cmd.perm; + +import org.onap.aaf.auth.cmd.Cmd; +import org.onap.aaf.auth.cmd.Param; +import org.onap.aaf.auth.rserv.HttpMethods; +import org.onap.aaf.cadi.CadiException; +import org.onap.aaf.cadi.LocatorException; +import org.onap.aaf.cadi.client.Future; +import org.onap.aaf.cadi.client.Rcli; +import org.onap.aaf.misc.env.APIException; + +import aaf.v2_0.Perms; + +/** + * Return Perms by Role + * + * @author Jeremiah + * + */ +public class ListByRole extends Cmd { + private static final String HEADER = "List Perms by Role "; + + public ListByRole(List parent) { + super(parent,"role", + new Param("name",true)); + } + + public int _exec(final int idx, final String ... args) throws CadiException, APIException, LocatorException { + final String role=args[idx]; + + return same(((List)parent).new ListPerms() { + @Override + public Integer code(Rcli client) throws CadiException, APIException { + + Future fp = client.read( + "/authz/perms/role/"+role+(aafcli.isDetailed()?"?ns":""), + getDF(Perms.class) + ); + return list(fp, HEADER, role); + } + }); + } + + @Override + public void detailedHelp(int indent, StringBuilder sb) { + detailLine(sb,indent,HEADER); + api(sb,indent,HttpMethods.GET,"authz/perms/role/",Perms.class,true); + } + + +} diff --git a/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/perm/ListByUser.java b/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/perm/ListByUser.java new file mode 100644 index 00000000..ba708273 --- /dev/null +++ b/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/perm/ListByUser.java @@ -0,0 +1,82 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.cmd.perm; + +import org.onap.aaf.auth.cmd.Cmd; +import org.onap.aaf.auth.cmd.Param; +import org.onap.aaf.auth.rserv.HttpMethods; +import org.onap.aaf.cadi.CadiException; +import org.onap.aaf.cadi.LocatorException; +import org.onap.aaf.cadi.client.Future; +import org.onap.aaf.cadi.client.Rcli; +import org.onap.aaf.misc.env.APIException; + +import aaf.v2_0.Perms; + +/** + * + * @author Jonathan + * + */ +public class ListByUser extends Cmd { + private static final String HEADER = "List Permissions by User"; + public ListByUser(List parent) { + super(parent,"user", + new Param("id",true)); + } + + public int _exec( int idx, final String ... args) throws CadiException, APIException, LocatorException { + final String user=fullID(args[idx]); + + return same(((List)parent).new ListPerms() { + @Override + public Integer code(Rcli client) throws CadiException, APIException { + StringBuilder sb = null; + if("true".equalsIgnoreCase(aafcli.forceString())) { + sb = new StringBuilder(); + sb.append("?force"); + } + if(aafcli.isDetailed()) { + if(sb==null) { + sb = new StringBuilder('?'); + } else { + sb.append('&'); + } + sb.append("ns"); + } + Future fp = client.read( + "/authz/perms/user/"+user+(sb==null?"":sb), + getDF(Perms.class) + ); + return list(fp,HEADER, user); + } + }); + } + + @Override + public void detailedHelp(int indent, StringBuilder sb) { + detailLine(sb,indent,HEADER); + api(sb,indent,HttpMethods.GET,"authz/perms/user/",Perms.class,true); + } + + +} diff --git a/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/perm/Perm.java b/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/perm/Perm.java new file mode 100644 index 00000000..805b6e62 --- /dev/null +++ b/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/perm/Perm.java @@ -0,0 +1,42 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.cmd.perm; + +import org.onap.aaf.auth.cmd.BaseCmd; +import org.onap.aaf.auth.cmd.role.Role; +import org.onap.aaf.misc.env.APIException; + +public class Perm extends BaseCmd { + Role role; + + public Perm(Role role) throws APIException { + super(role.aafcli, "perm"); + this.role = role; + + cmds.add(new Create(this)); + cmds.add(new Delete(this)); + cmds.add(new Grant(this)); + cmds.add(new Rename(this)); + cmds.add(new Describe(this)); + cmds.add(new List(this)); + } +} diff --git a/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/perm/Rename.java b/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/perm/Rename.java new file mode 100644 index 00000000..fa65f61a --- /dev/null +++ b/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/perm/Rename.java @@ -0,0 +1,102 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.cmd.perm; + + +import org.onap.aaf.auth.cmd.AAFcli; +import org.onap.aaf.auth.cmd.Cmd; +import org.onap.aaf.auth.cmd.Param; +import org.onap.aaf.auth.rserv.HttpMethods; +import org.onap.aaf.cadi.CadiException; +import org.onap.aaf.cadi.LocatorException; +import org.onap.aaf.cadi.client.Future; +import org.onap.aaf.cadi.client.Rcli; +import org.onap.aaf.cadi.client.Retryable; +import org.onap.aaf.misc.env.APIException; + +import aaf.v2_0.PermRequest; + +public class Rename extends Cmd { + public Rename(Perm parent) { + super(parent,"rename", + new Param("type",true), + new Param("instance",true), + new Param("action", true), + new Param("new type",true), + new Param("new instance",true), + new Param("new action", true) + ); + } + + @Override + public int _exec(final int index, final String ... args) throws CadiException, APIException, LocatorException { + return same(new Retryable() { + @Override + public Integer code(Rcli client) throws CadiException, APIException { + int idx = index; + String origType = args[idx++]; + String origInstance = args[idx++]; + String origAction = args[idx++]; + + //Create new permission + PermRequest pr = new PermRequest(); + pr.setType(args[idx++]); + pr.setInstance(args[idx++]); + pr.setAction(args[idx++]); + + // Set Start/End commands + setStartEnd(pr); + Future fp = client.update( + "/authz/perm/"+origType+"/"+origInstance+"/"+origAction, + getDF(PermRequest.class), + pr + ); + int rv; + if(fp.get(AAFcli.timeout())) { + rv = fp.code(); + pw().println("Updated Permission"); + } else { + rv = fp.code(); + if(rv==202) { + pw().println("Permission Update Accepted, but requires Approvals before actualizing"); + } else { + error(fp); + } + } + return rv; + } + }); + + } + + @Override + public void detailedHelp(int indent, StringBuilder sb) { + detailLine(sb,indent,"Rename a Permission from:"); + detailLine(sb,indent+2," "); + detailLine(sb,indent,"to:"); + detailLine(sb,indent+2," "); + sb.append('\n'); + detailLine(sb,indent,"Namespace must be the same in and "); + detailLine(sb,indent+4,"see Create for definitions of type,instance and action"); + api(sb,indent,HttpMethods.PUT,"authz/perm///",PermRequest.class,true); + } +} diff --git a/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/role/CreateDelete.java b/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/role/CreateDelete.java new file mode 100644 index 00000000..99d55839 --- /dev/null +++ b/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/role/CreateDelete.java @@ -0,0 +1,130 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.cmd.role; + +import org.onap.aaf.auth.cmd.AAFcli; +import org.onap.aaf.auth.cmd.Cmd; +import org.onap.aaf.auth.cmd.Param; +import org.onap.aaf.auth.rserv.HttpMethods; +import org.onap.aaf.cadi.CadiException; +import org.onap.aaf.cadi.LocatorException; +import org.onap.aaf.cadi.client.Future; +import org.onap.aaf.cadi.client.Rcli; +import org.onap.aaf.cadi.client.Retryable; +import org.onap.aaf.misc.env.APIException; + +import aaf.v2_0.RoleRequest; + +/** + * + * @author Jonathan + * + */ +public class CreateDelete extends Cmd { + private static final String ROLE_PATH = "/authz/role"; + private final static String[] options = {"create","delete"}; + public CreateDelete(Role parent) { + super(parent,null, + new Param(optionsToString(options),true), + new Param("name",true)); + } + + @Override + public int _exec(final int index, final String ... args) throws CadiException, APIException, LocatorException { + return same(new Retryable() { + @Override + public Integer code(Rcli client) throws CadiException, APIException { + int idx = index; + String action = args[idx++]; + int option = whichOption(options, action); + + RoleRequest rr = new RoleRequest(); + rr.setName(args[idx++]); + + // Set Start/End commands + setStartEnd(rr); + + Future fp = null; + String verb = null; + int rv; + switch(option) { + case 0: + fp = client.create( + ROLE_PATH, + getDF(RoleRequest.class), + rr + ); + verb = "Create"; + break; + case 1: + // Send "Force" if set + setQueryParamsOn(client); + fp = client.delete( + ROLE_PATH, // +args[idx++], + getDF(RoleRequest.class), + rr + ); + verb = "Delete"; + break; + default: // note, if not an option, whichOption throws Exception + break; + + } + boolean rolesSupplied = (args.length>idx); + if(fp.get(AAFcli.timeout())) { + rv=fp.code(); + pw().print(verb); + pw().println("d Role"); + if(rolesSupplied) { + for(;args.length>idx;++idx ) { + try { + if(201!=(rv=((Role)parent)._exec(0,new String[] {"user","add",rr.getName(),args[idx]}))) { + rv = 206 /*HttpStatus.PARTIAL_CONTENT_206*/; + } + } catch (LocatorException e) { + throw new CadiException(e); + } + } + } + } else { + if((rv=fp.code())==202) { + pw().print("Role "); + pw().print(verb); + pw().println(" Accepted, but requires Approvals before actualizing"); + } else { + error(fp); + } + } + return rv; + } + }); + } + + @Override + public void detailedHelp(int indent, StringBuilder sb) { + detailLine(sb,indent,"Create OR Delete a Role"); + detailLine(sb,indent+2,"name - Name of Role to create"); + api(sb,indent,HttpMethods.POST,"authz/role",RoleRequest.class,true); + api(sb,indent,HttpMethods.DELETE,"authz/role",RoleRequest.class,false); + } + +} diff --git a/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/role/Describe.java b/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/role/Describe.java new file mode 100644 index 00000000..5498f29a --- /dev/null +++ b/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/role/Describe.java @@ -0,0 +1,94 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.cmd.role; + +import org.onap.aaf.auth.cmd.AAFcli; +import org.onap.aaf.auth.cmd.Cmd; +import org.onap.aaf.auth.cmd.Param; +import org.onap.aaf.auth.rserv.HttpMethods; +import org.onap.aaf.cadi.CadiException; +import org.onap.aaf.cadi.LocatorException; +import org.onap.aaf.cadi.client.Future; +import org.onap.aaf.cadi.client.Rcli; +import org.onap.aaf.cadi.client.Retryable; +import org.onap.aaf.misc.env.APIException; + +import aaf.v2_0.RoleRequest; + +public class Describe extends Cmd { + private static final String ROLE_PATH = "/authz/role"; + public Describe(Role parent) { + super(parent,"describe", + new Param("name",true), + new Param("description",true)); + } + + @Override + public int _exec(final int index, final String ... args) throws CadiException, APIException, LocatorException { + return same(new Retryable() { + @Override + public Integer code(Rcli client) throws CadiException, APIException { + int idx = index; + String role = args[idx++]; + StringBuilder desc = new StringBuilder(); + while (idx < args.length) { + desc.append(args[idx++] + ' '); + } + + RoleRequest rr = new RoleRequest(); + rr.setName(role); + rr.setDescription(desc.toString()); + + // Set Start/End commands + setStartEnd(rr); + + Future fp = null; + int rv; + + fp = client.update( + ROLE_PATH, + getDF(RoleRequest.class), + rr + ); + + if(fp.get(AAFcli.timeout())) { + rv=fp.code(); + pw().println("Description added to role"); + } else { + if((rv=fp.code())==202) { + pw().print("Adding description"); + pw().println(" Accepted, but requires Approvals before actualizing"); + } else { + error(fp); + } + } + return rv; + } + }); + } + + @Override + public void detailedHelp(int indent, StringBuilder sb) { + detailLine(sb,indent,"Add a description to a role"); + api(sb,indent,HttpMethods.PUT,"authz/role",RoleRequest.class,true); + } +} diff --git a/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/role/List.java b/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/role/List.java new file mode 100644 index 00000000..2e09b03b --- /dev/null +++ b/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/role/List.java @@ -0,0 +1,211 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.cmd.role; + +import java.util.Collections; +import java.util.Comparator; + +import javax.xml.datatype.XMLGregorianCalendar; + +import org.onap.aaf.auth.cmd.AAFcli; +import org.onap.aaf.auth.cmd.BaseCmd; +import org.onap.aaf.cadi.CadiException; +import org.onap.aaf.cadi.client.Future; +import org.onap.aaf.cadi.client.Rcli; +import org.onap.aaf.cadi.client.Retryable; +import org.onap.aaf.misc.env.APIException; +import org.onap.aaf.misc.env.util.Chrono; + +import aaf.v2_0.Perm; +import aaf.v2_0.Perms; +import aaf.v2_0.Pkey; +import aaf.v2_0.Roles; +import aaf.v2_0.UserRole; +import aaf.v2_0.UserRoles; + + + +public class List extends BaseCmd { + private static final String XXXX_XX_XX = "XXXX-XX-XX"; + private static final String LIST_ROLES_BY_NAME = "list roles for role"; + + public List(Role parent) { + super(parent,"list"); + cmds.add(new ListByUser(this)); + cmds.add(new ListByRole(this)); + cmds.add(new ListByNS(this)); + cmds.add(new ListByNameOnly(this)); + cmds.add(new ListByPerm(this)); + cmds.add(new ListActivity(this)); + } + + // Package Level on purpose + abstract class ListRoles extends Retryable { + protected int list(Future fr,Rcli client, String header) throws APIException, CadiException { + if(fr.get(AAFcli.timeout())) { + Perms perms=null; + if (aafcli.isDetailed()) { + for(aaf.v2_0.Role r : fr.value.getRole()) { + Future fp = client.read( + "/authz/perms/role/"+r.getName()+(aafcli.isDetailed()?"?ns":""), + getDF(Perms.class) + ); + if(fp.get(AAFcli.timeout())) { + if(perms==null) { + perms = fp.value; + } else { + perms.getPerm().addAll(fp.value.getPerm()); + } + } + } + } + report(fr.value,perms,null,header); + } else { + error(fr); + } + return fr.code(); + } + } + + private final static String roleFormat = "%-56s Expires %s\n"; + private final static String roleFormatNoDate = "%-61s\n"; + private final static String roleExpiredFormat = "%-53s !!! EXPIRED !!! %s\n"; + private final static String permFormat = " %-30s %-30s %-15s\n"; + + + private static final Comparator roleCompare = new Comparator() { + @Override + public int compare(aaf.v2_0.Role a, aaf.v2_0.Role b) { + return a.getName().compareTo(b.getName()); + } + }; + public void report(Roles roles, Perms perms, UserRoles urs, String ... str) { + reportHead(str); + XMLGregorianCalendar now = Chrono.timeStamp().normalize(); + if(roles==null || roles.getRole().isEmpty()) { + pw().println(""); + } else if (aafcli.isDetailed()){ + if (aafcli.isDetailed() && str[0].toLowerCase().contains(LIST_ROLES_BY_NAME)) { + String description = roles.getRole().get(0).getDescription(); + if (description == null) description = ""; + reportColHead("%-80s\n","Description: " + description); + } + + String fullFormat = roleFormat+permFormat; + reportColHead(fullFormat,"[ROLE NS].Name","","[PERM NS].Type","Instance","Action"); + Collections.sort(roles.getRole(),roleCompare); + for(aaf.v2_0.Role r : roles.getRole()) { + String roleName = r.getName(); + String ns = r.getNs(); + if(aafcli.isTest()) { + if(ns==null) { + pw().format(roleFormat, roleName,XXXX_XX_XX); + } else { + pw().format(roleFormat, "["+ns+"]"+roleName.substring(ns.length()),XXXX_XX_XX); + } + } else { + UserRole ur = get(roleName,urs); + if(ur!=null && now.compare(ur.getExpires().normalize())>0) { + if(ns==null) { + pw().format(roleExpiredFormat, roleName,Chrono.dateOnlyStamp(ur.getExpires())); + } else { + pw().format(roleExpiredFormat, "["+ns+"]"+roleName.substring(ns.length()),Chrono.dateOnlyStamp(ur.getExpires())); + } + } else { + if(ns==null) { + pw().format(roleFormat, roleName,ur!=null?Chrono.dateOnlyStamp(ur.getExpires()):""); + } else { + pw().format(roleFormat, "["+ns+"]"+roleName.substring(ns.length()),ur!=null?Chrono.dateOnlyStamp(ur.getExpires()):""); + } + } + } + + for(Pkey pkey : r.getPerms()) { + Perm perm = get(pkey,perms); + if(perm==null || perm.getNs()==null) { + pw().format(permFormat, + pkey.getType(), + pkey.getInstance(), + pkey.getAction()); + } else { + String ns1 = perm.getNs(); + pw().format(permFormat, + '['+ns1+"]"+perm.getType().substring(ns1.length()), + perm.getInstance(), + perm.getAction()); + } + } + } + } else { + String fullFormat = roleFormat; + reportColHead(fullFormat,"ROLE Name","","PERM Type","Instance","Action"); + Collections.sort(roles.getRole(),roleCompare); + for(aaf.v2_0.Role r : roles.getRole()) { + if (urs != null) { + String roleName = r.getName(); + if(!aafcli.isTest()) { + UserRole ur = get(roleName,urs); + if(ur!=null && now.compare(ur.getExpires().normalize())>0) { + pw().format(roleExpiredFormat, roleName+"*",Chrono.dateOnlyStamp(ur.getExpires())); + } else { + pw().format(roleFormat, roleName,ur!=null?Chrono.dateOnlyStamp(ur.getExpires()):""); + } + } else { + pw().format(roleFormat, roleName,XXXX_XX_XX); + } + } else { + pw().format(roleFormatNoDate, r.getName()); + for(Pkey perm : r.getPerms()) { + pw().format(permFormat, + perm.getType(), + perm.getInstance(), + perm.getAction()); + } + } + } + } + } + private Perm get(Pkey pkey, Perms perms) { + if(perms!=null) { + for(Perm p : perms.getPerm()) { + if(pkey.getAction().equals(p.getAction()) && + pkey.getInstance().equals(p.getInstance()) && + pkey.getType().equals(p.getType())) { + return p; + } + } + } + return null; + } + // The assumption is that these UserRoles are already pulled in by User... no need to check + private UserRole get(String roleName, UserRoles urs) { + if(urs!=null) { + for(UserRole ur : urs.getUserRole()) { + if(roleName.equals(ur.getRole())) { + return ur; + } + } + } + return null; + } + +} diff --git a/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/role/ListActivity.java b/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/role/ListActivity.java new file mode 100644 index 00000000..0331ae09 --- /dev/null +++ b/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/role/ListActivity.java @@ -0,0 +1,75 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.cmd.role; + +import org.onap.aaf.auth.cmd.AAFcli; +import org.onap.aaf.auth.cmd.Cmd; +import org.onap.aaf.auth.cmd.Param; +import org.onap.aaf.auth.rserv.HttpMethods; +import org.onap.aaf.cadi.CadiException; +import org.onap.aaf.cadi.LocatorException; +import org.onap.aaf.cadi.client.Future; +import org.onap.aaf.cadi.client.Rcli; +import org.onap.aaf.cadi.client.Retryable; +import org.onap.aaf.misc.env.APIException; + +import aaf.v2_0.History; + +/** + * * @author Jonathan + * + */ +public class ListActivity extends Cmd { + private static final String HEADER = "List Activity of Role"; + + public ListActivity(List parent) { + super(parent,"activity", + new Param("name",true)); + } + + @Override + public int _exec(int _idx, final String ... args) throws CadiException, APIException, LocatorException { + int idx = _idx; + final String role = args[idx++]; + return same(new Retryable() { + @Override + public Integer code(Rcli client) throws CadiException, APIException { + Future fp = client.read( + "/authz/hist/role/"+role, + getDF(History.class) + ); + if(fp.get(AAFcli.timeout())) { + activity(fp.value,HEADER + " [ " + role + " ]"); + } else { + error(fp); + } + return fp.code(); + } + }); + } + + @Override + public void detailedHelp(int indent, StringBuilder sb) { + detailLine(sb,indent,HEADER); + api(sb,indent,HttpMethods.GET,"authz/hist/role/",History.class,true); + } +} diff --git a/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/role/ListByNS.java b/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/role/ListByNS.java new file mode 100644 index 00000000..11476f10 --- /dev/null +++ b/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/role/ListByNS.java @@ -0,0 +1,72 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.cmd.role; + +import org.onap.aaf.auth.cmd.Cmd; +import org.onap.aaf.auth.cmd.Param; +import org.onap.aaf.auth.rserv.HttpMethods; +import org.onap.aaf.cadi.CadiException; +import org.onap.aaf.cadi.LocatorException; +import org.onap.aaf.cadi.client.Future; +import org.onap.aaf.cadi.client.Rcli; +import org.onap.aaf.misc.env.APIException; + +import aaf.v2_0.Roles; + +/** + * Return Roles by NS + * + * @author Jonathan + * + */ +public class ListByNS extends Cmd { + private static final String HEADER = "List Roles by NS "; + + public ListByNS(List parent) { + super(parent,"ns", + new Param("name",true)); + } + + @Override + public int _exec( int idx, final String ... args) throws CadiException, APIException, LocatorException { + final String ns=args[idx]; + + return same(((List)parent).new ListRoles() { + @Override + public Integer code(Rcli client) throws CadiException, APIException { + Future fp = client.read( + "/authz/roles/ns/"+ns+(aafcli.isDetailed()?"?ns":""), + getDF(Roles.class) + ); + return list(fp,client, HEADER+"["+ns+"]"); + } + }); + } + + @Override + public void detailedHelp(int indent, StringBuilder sb) { + detailLine(sb,indent,HEADER); + api(sb,indent,HttpMethods.GET,"authz/roles/name/",Roles.class,true); + } + + +} diff --git a/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/role/ListByNameOnly.java b/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/role/ListByNameOnly.java new file mode 100644 index 00000000..81b86718 --- /dev/null +++ b/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/role/ListByNameOnly.java @@ -0,0 +1,72 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.cmd.role; + +import org.onap.aaf.auth.cmd.Cmd; +import org.onap.aaf.auth.cmd.Param; +import org.onap.aaf.auth.rserv.HttpMethods; +import org.onap.aaf.cadi.CadiException; +import org.onap.aaf.cadi.LocatorException; +import org.onap.aaf.cadi.client.Future; +import org.onap.aaf.cadi.client.Rcli; +import org.onap.aaf.misc.env.APIException; + +import aaf.v2_0.Roles; + +/** + * Return Roles by NS + * + * @author Jonathan + * + */ +public class ListByNameOnly extends Cmd { + private static final String HEADER = "List Roles by Name "; + + public ListByNameOnly(List parent) { + super(parent,"name", + new Param("name",true)); + } + + @Override + public int _exec( int idx, final String ... args) throws CadiException, APIException, LocatorException { + final String name=args[idx]; + + return same(((List)parent).new ListRoles() { + @Override + public Integer code(Rcli client) throws CadiException, APIException { + Future fp = client.read( + "/authz/roles/name/"+name+(aafcli.isDetailed()?"?ns":""), + getDF(Roles.class) + ); + return list(fp,client, HEADER+"["+name+"]"); + } + }); + } + + @Override + public void detailedHelp(int indent, StringBuilder sb) { + detailLine(sb,indent,HEADER); + api(sb,indent,HttpMethods.GET,"authz/roles/name/",Roles.class,true); + } + + +} diff --git a/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/role/ListByPerm.java b/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/role/ListByPerm.java new file mode 100644 index 00000000..cb18eb34 --- /dev/null +++ b/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/role/ListByPerm.java @@ -0,0 +1,78 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.cmd.role; + +import org.onap.aaf.auth.cmd.Cmd; +import org.onap.aaf.auth.cmd.Param; +import org.onap.aaf.auth.rserv.HttpMethods; +import org.onap.aaf.cadi.CadiException; +import org.onap.aaf.cadi.LocatorException; +import org.onap.aaf.cadi.client.Future; +import org.onap.aaf.cadi.client.Rcli; +import org.onap.aaf.misc.env.APIException; + +import aaf.v2_0.Roles; + +/** + * Return Roles by NS + * + * @author Jonathan + * + */ +public class ListByPerm extends Cmd { + private static final String HEADER = "List Roles by Perm "; + + public ListByPerm(List parent) { + super(parent,"perm", + new Param("type",true), + new Param("instance", true), + new Param("action", true)); + } + + @Override + public int _exec(int _idx, final String ... args) throws CadiException, APIException, LocatorException { + int idx = _idx; + final String type=args[idx]; + final String instance=args[++idx]; + final String action=args[++idx]; + + return same(((List)parent).new ListRoles() { + @Override + public Integer code(Rcli client) throws CadiException, APIException { + + Future fp = client.read( + "/authz/roles/perm/"+type+'/'+instance+'/'+action, + getDF(Roles.class) + ); + return list(fp,client, HEADER+type+'|'+instance+'|'+action); + } + }); + } + + @Override + public void detailedHelp(int indent, StringBuilder sb) { + detailLine(sb,indent,HEADER); + api(sb,indent,HttpMethods.GET,"authz/roles/user/",Roles.class,true); + } + + +} diff --git a/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/role/ListByRole.java b/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/role/ListByRole.java new file mode 100644 index 00000000..0fafbd92 --- /dev/null +++ b/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/role/ListByRole.java @@ -0,0 +1,69 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.cmd.role; + +import org.onap.aaf.auth.cmd.Cmd; +import org.onap.aaf.auth.cmd.Param; +import org.onap.aaf.auth.rserv.HttpMethods; +import org.onap.aaf.cadi.CadiException; +import org.onap.aaf.cadi.LocatorException; +import org.onap.aaf.cadi.client.Future; +import org.onap.aaf.cadi.client.Rcli; +import org.onap.aaf.misc.env.APIException; + +import aaf.v2_0.Roles; + +/** + * + * @author Jonathan + * + */ +public class ListByRole extends Cmd { + private static final String HEADER="List Roles for Role"; + + public ListByRole(List parent) { + super(parent,"role", + new Param("role",true)); + } + + @Override + public int _exec(final int idx, final String ... args) throws CadiException, APIException, LocatorException { + return same(((List)parent).new ListRoles() { + @Override + public Integer code(Rcli client) throws CadiException, APIException { + String role=args[idx]; + Future fp = client.read( + "/authz/roles/"+role+(aafcli.isDetailed()?"?ns":""), + getDF(Roles.class) + ); + return list(fp,client,HEADER+"["+role+"]"); + } + }); + } + + @Override + public void detailedHelp(int indent, StringBuilder sb) { + detailLine(sb,indent,HEADER); + api(sb,indent,HttpMethods.GET,"authz/roles/",Roles.class,true); + } + +} diff --git a/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/role/ListByUser.java b/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/role/ListByUser.java new file mode 100644 index 00000000..7165de67 --- /dev/null +++ b/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/role/ListByUser.java @@ -0,0 +1,99 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.cmd.role; + +import org.onap.aaf.auth.cmd.AAFcli; +import org.onap.aaf.auth.cmd.Cmd; +import org.onap.aaf.auth.cmd.Param; +import org.onap.aaf.auth.rserv.HttpMethods; +import org.onap.aaf.cadi.CadiException; +import org.onap.aaf.cadi.LocatorException; +import org.onap.aaf.cadi.client.Future; +import org.onap.aaf.cadi.client.Rcli; +import org.onap.aaf.cadi.client.Retryable; +import org.onap.aaf.misc.env.APIException; + +import aaf.v2_0.Perms; +import aaf.v2_0.Roles; +import aaf.v2_0.UserRoles; + +/** + * p + * @author Jonathan + * + */ +public class ListByUser extends Cmd { + private static final String HEADER = "List Roles for User "; + + public ListByUser(List parent) { + super(parent,"user", + new Param("id",true), + new Param("detail", false)); + } + + @Override + public int _exec( int idx, final String ... args) throws CadiException, APIException, LocatorException { + final String user=fullID(args[idx]); + + + return same(new Retryable() { + @Override + public Integer code(Rcli client) throws CadiException, APIException { + Perms perms=null; + UserRoles urs=null; + Future fr = client.read( + "/authz/roles/user/"+user+(aafcli.isDetailed()?"?ns":""), + getDF(Roles.class) + ); + Future fur = client.read( + "/authz/userRoles/user/"+user, + getDF(UserRoles.class) + ); + if(fr.get(AAFcli.timeout())) { + if (aafcli.isDetailed()) { + Future fp = client.read( + "/authz/perms/user/"+user+(aafcli.isDetailed()?"?ns":""), + getDF(Perms.class) + ); + if(fp.get(AAFcli.timeout())) { + perms = fp.value; + } + } + if (fur.get(AAFcli.timeout())) { + urs = fur.value; + } + + ((List)parent).report(fr.value,perms,urs,HEADER,user); + } else { + error(fr); + } + return fr.code(); + } + }); + } + + @Override + public void detailedHelp(int indent, StringBuilder sb) { + detailLine(sb,indent,HEADER); + api(sb,indent,HttpMethods.GET,"authz/roles/user/",Roles.class,true); + } +} diff --git a/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/role/Role.java b/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/role/Role.java new file mode 100644 index 00000000..f28654ee --- /dev/null +++ b/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/role/Role.java @@ -0,0 +1,39 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.cmd.role; + +import org.onap.aaf.auth.cmd.AAFcli; +import org.onap.aaf.auth.cmd.BaseCmd; +import org.onap.aaf.misc.env.APIException; + +public class Role extends BaseCmd { + public List list; + + public Role(AAFcli aafcli) throws APIException { + super(aafcli, "role"); + cmds.add(new CreateDelete(this)); +// cmds.add(new Delete(this)); + cmds.add(new User(this)); + cmds.add(new Describe(this)); + cmds.add(list = new List(this)); + } +} diff --git a/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/role/User.java b/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/role/User.java new file mode 100644 index 00000000..181804b9 --- /dev/null +++ b/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/role/User.java @@ -0,0 +1,169 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.cmd.role; + +import org.onap.aaf.auth.cmd.AAFcli; +import org.onap.aaf.auth.cmd.Cmd; +import org.onap.aaf.auth.cmd.Param; +import org.onap.aaf.auth.rserv.HttpMethods; +import org.onap.aaf.cadi.CadiException; +import org.onap.aaf.cadi.LocatorException; +import org.onap.aaf.cadi.client.Future; +import org.onap.aaf.cadi.client.Rcli; +import org.onap.aaf.cadi.client.Retryable; +import org.onap.aaf.misc.env.APIException; + +import aaf.v2_0.UserRoleRequest; + +/** + * p + * @author Jonathan + * + */ +public class User extends Cmd { + private final static String[] options = {"add","del","setTo","extend"}; + public User(Role parent) { + super(parent,"user", + new Param(optionsToString(options),true), + new Param("role",true), + new Param("id[,id]* (not required for setTo)",false)); + } + + @Override + public int _exec(final int index, final String ... args) throws CadiException, APIException, LocatorException { + return same(new Retryable() { + @Override + public Integer code(Rcli client) throws CadiException, APIException { + int idx = index; + String action = args[idx++]; + int option = whichOption(options, action); + UserRoleRequest urr = new UserRoleRequest(); + urr.setRole(args[idx++]); + // Set Start/End commands + setStartEnd(urr); + + Future fp = null; + + if (option != 2) { + String[] ids = args[idx++].split(","); + String verb=null,participle=null; + // You can request to be added or removed from role. + setQueryParamsOn(client); + + for(String id: ids) { + id=fullID(id); + urr.setUser(id); + switch(option) { + case 0: + fp = client.create( + "/authz/userRole", + getDF(UserRoleRequest.class), + urr); + verb = "Added"; + participle = "] to Role [" ; + break; + case 1: + fp = client.delete( + "/authz/userRole/"+urr.getUser()+'/'+urr.getRole(), + Void.class); + verb = "Removed"; + participle = "] from Role [" ; + break; + case 3: + fp = client.update("/authz/userRole/extend/" + urr.getUser() + '/' + urr.getRole()); + verb = "Extended"; + participle = "] in Role [" ; + break; + + default: // actually, should never get here... + throw new CadiException("Invalid action [" + action + ']'); + } + if(fp.get(AAFcli.timeout())) { + pw().print(verb); + pw().print(" User ["); + pw().print(urr.getUser()); + pw().print(participle); + pw().print(urr.getRole()); + pw().println(']'); + } else { + switch(fp.code()) { + case 202: + pw().print("User Role "); + pw().print(action); + pw().println(" is Accepted, but requires Approvals before actualizing"); + break; + case 404: + if(option==3) { + pw().println("Failed with code 404: UserRole is not found, or you do not have permission to view"); + break; + } + default: + error(fp); + } + } + } + } else { + String allUsers = ""; + if (idx < args.length) + allUsers = args[idx++]; + StringBuilder finalUsers = new StringBuilder(); + for (String u : allUsers.split(",")) { + if (u != "") { + u=fullID(u); + if (finalUsers.length() > 0) finalUsers.append(","); + finalUsers.append(u); + } + } + + urr.setUser(finalUsers.toString()); + fp = client.update( + "/authz/userRole/role", + getDF(UserRoleRequest.class), + urr); + if(fp.get(AAFcli.timeout())) { + pw().println("Set the Role to Users [" + allUsers + "]"); + } else { + error(fp); + } + } + return fp==null?0:fp.code(); + } + }); + } + + @Override + public void detailedHelp(int indent, StringBuilder sb) { + detailLine(sb,indent,"Add OR Delete a User to/from a Role OR"); + detailLine(sb,indent,"Set a User's Roles to the roles supplied"); + detailLine(sb,indent+2,"role - Name of Role to create"); + detailLine(sb,indent+2,"id(s) - ID or IDs to add to the Role"); + sb.append('\n'); + detailLine(sb,indent+2,"Note: this is the same as \"user role add...\" except allows"); + detailLine(sb,indent+2,"assignment of role to multiple userss"); + detailLine(sb,indent+2,"WARNING: Users supplied with setTo will be the ONLY users attached to this role"); + detailLine(sb,indent+2,"If no users are supplied, the users attached to this role are reset."); + api(sb,indent,HttpMethods.POST,"authz/userRole",UserRoleRequest.class,true); + api(sb,indent,HttpMethods.DELETE,"authz/userRole//",Void.class,false); + api(sb,indent,HttpMethods.PUT,"authz/userRole/",UserRoleRequest.class,false); + } + +} diff --git a/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/user/Cred.java b/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/user/Cred.java new file mode 100644 index 00000000..4bb2ae30 --- /dev/null +++ b/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/user/Cred.java @@ -0,0 +1,154 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.cmd.user; + +import org.onap.aaf.auth.cmd.AAFcli; +import org.onap.aaf.auth.cmd.Cmd; +import org.onap.aaf.auth.cmd.Param; +import org.onap.aaf.auth.rserv.HttpMethods; +import org.onap.aaf.cadi.CadiException; +import org.onap.aaf.cadi.LocatorException; +import org.onap.aaf.cadi.client.Future; +import org.onap.aaf.cadi.client.Rcli; +import org.onap.aaf.cadi.client.Retryable; +import org.onap.aaf.misc.env.APIException; + +import aaf.v2_0.CredRequest; + +public class Cred extends Cmd { + public static final String ATTEMPT_FAILED_SPECIFICS_WITHELD = "Attempt Failed. Specifics witheld."; + private static final String CRED_PATH = "/authn/cred"; + private static final String[] options = {"add","del","reset","extend"/*,"clean"*/}; +// private Clean clean; + public Cred(User parent) { + super(parent,"cred", + new Param(optionsToString(options),true), + new Param("id",true), + new Param("password (! D|E)",false), + new Param("entry# (if multi)",false) + ); +// clean = new Clean(this); + } + + @Override + public int _exec(int _idx, final String ... args) throws CadiException, APIException, LocatorException { + int idx = _idx; + String key = args[idx++]; + final int option = whichOption(options,key); + + final CredRequest cr = new CredRequest(); + cr.setId(args[idx++]); + if(option!=1 && option!=3) { + if(idx>=args.length) throw new CadiException("Password Required"); + cr.setPassword(args[idx++]); + } + if(args.length>idx) + cr.setEntry(args[idx++]); + + // Set Start/End commands + setStartEnd(cr); +// final int cleanIDX = _idx+1; + Integer ret = same(new Retryable() { + @Override + public Integer code(Rcli client) throws CadiException, APIException { + Future fp=null; + String verb =null; + switch(option) { + case 0: + fp = client.create( + CRED_PATH, + getDF(CredRequest.class), + cr + ); + verb = "Added Credential ["; + break; + case 1: +// if(aafcli.addForce())cr.setForce("TRUE"); + setQueryParamsOn(client); + fp = client.delete(CRED_PATH, + getDF(CredRequest.class), + cr + ); + verb = "Deleted Credential ["; + break; + case 2: + fp = client.update( + CRED_PATH, + getDF(CredRequest.class), + cr + ); + verb = "Reset Credential ["; + break; + case 3: + fp = client.update( + CRED_PATH+"/5", + getDF(CredRequest.class), + cr + ); + verb = "Extended Credential ["; + break; +// case 4: +// return clean.exec(cleanIDX, args); + } + if(fp.get(AAFcli.timeout())) { + pw().print(verb); + pw().print(cr.getId()); + pw().println(']'); + } else if(fp.code()==202) { + pw().println("Credential Action Accepted, but requires Approvals before actualizing"); + } else if(fp.code()==406 && option==1) { + pw().println("You cannot delete this Credential"); + } else { + pw().println(ATTEMPT_FAILED_SPECIFICS_WITHELD); + } + return fp.code(); + } + }); + if(ret==null)ret = -1; + return ret; + } + + @Override + public void detailedHelp(int _indent, StringBuilder sb) { + int indent = _indent; + detailLine(sb,indent,"Add, Delete or Reset Credential"); + indent+=2; + detailLine(sb,indent,"id - the ID to create/delete/reset within AAF"); + detailLine(sb,indent,"password - Company Policy compliant Password (not required for Delete)"); + detailLine(sb,indent,"entry - selected option when deleting/resetting a cred with multiple entries"); + sb.append('\n'); + detailLine(sb,indent,"The Domain can be related to any Namespace you have access to *"); + detailLine(sb,indent,"The Domain is in reverse order of Namespace, i.e. "); + detailLine(sb,indent+2,"NS of com.att.myapp can create user of XY1234@myapp.att.com"); + sb.append('\n'); + detailLine(sb,indent,"NOTE: AAF does support multiple creds with the same ID. Check with your org if you"); + detailLine(sb,indent+2,"have this implemented. (For example, this is implemented for MechIDs at AT&T)"); + sb.append('\n'); + detailLine(sb,indent,"*NOTE: com.att.csp is a reserved Domain for Global Sign On"); + + detailLine(sb,indent,"Delegates can be listed by the User or by the Delegate"); + indent-=2; + api(sb,indent,HttpMethods.POST,"authn/cred",CredRequest.class,true); + api(sb,indent,HttpMethods.DELETE,"authn/cred",CredRequest.class,false); + api(sb,indent,HttpMethods.PUT,"authn/cred",CredRequest.class,false); + } +} diff --git a/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/user/Delg.java b/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/user/Delg.java new file mode 100644 index 00000000..ec1aa5a0 --- /dev/null +++ b/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/user/Delg.java @@ -0,0 +1,131 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.cmd.user; + +import java.text.ParseException; +import java.util.Date; + +import org.onap.aaf.auth.cmd.AAFcli; +import org.onap.aaf.auth.cmd.BaseCmd; +import org.onap.aaf.auth.cmd.Param; +import org.onap.aaf.auth.rserv.HttpMethods; +import org.onap.aaf.cadi.CadiException; +import org.onap.aaf.cadi.LocatorException; +import org.onap.aaf.cadi.client.Future; +import org.onap.aaf.cadi.client.Rcli; +import org.onap.aaf.cadi.client.Retryable; +import org.onap.aaf.misc.env.APIException; +import org.onap.aaf.misc.env.util.Chrono; +import org.onap.aaf.misc.rosetta.env.RosettaDF; + +import aaf.v2_0.DelgRequest; + +public class Delg extends BaseCmd { + static final String AUTHZ_DELG = "/authz/delegate"; + private final static String[] options = {"add","upd","del"}; + + public Delg(User user) throws APIException { + super(user,"delegate", + new Param(optionsToString(options),true), + new Param("from",true), + new Param("to REQ A&U",false), + new Param("until (YYYY-MM-DD) REQ A", false) + ); + } + + @Override + public int _exec(final int index, final String ... args) throws CadiException, APIException, LocatorException { + return same(new Retryable() { + @Override + public Integer code(Rcli client) throws CadiException, APIException { + int idx = index; + DelgRequest dr = new DelgRequest(); + setStartEnd(dr); + + int option= whichOption(options, args[idx++]); + String user = fullID(args[idx++]); + dr.setUser(user); + if(option<2) { + String delegate = fullID(args[idx++]); + dr.setDelegate(delegate); + if(option<2 && args.length>idx) { + Date date; + try { + date = Chrono.dateOnlyFmt.parse(args[idx++]); + } catch (ParseException e) { + throw new CadiException(e); + } + dr.setEnd(Chrono.timeStamp(date)); + } + } + + Future fp; + RosettaDF df = getDF(DelgRequest.class); + String verb; + setQueryParamsOn(client); + + switch(option) { + case 0: + fp = client.create(AUTHZ_DELG, df, dr); + verb = "Added"; + break; + case 1: + fp = client.update(AUTHZ_DELG, df, dr); + verb = "Updated"; + break; + case 2: + fp = client.delete(AUTHZ_DELG, df, dr); + verb = "Deleted"; + break; + default: + throw new CadiException("Bad Argument"); + }; + + if(fp.get(AAFcli.timeout())) { + pw().append("Delegate "); + pw().println(verb); + } else { + error(fp); + } + return fp.code(); + } + }); + } + + @Override + public void detailedHelp(int _indent, StringBuilder sb) { + int indent = _indent; + detailLine(sb,indent,"Add, Update or Delete Delegate"); + indent+=2; + detailLine(sb,indent,"A Delegate is a person who will temporarily cover the Approval and"); + detailLine(sb,indent,"Ownership questions on behalf of the person Responsible."); + sb.append('\n'); + detailLine(sb,indent,"fromID - the person who is the Responsible person of record"); + detailLine(sb,indent,"toID - the person who will be delegated (required for Add/Update)"); + detailLine(sb,indent,"until - the end date for this delegation"); + indent-=2; + api(sb,indent,HttpMethods.POST,AUTHZ_DELG,DelgRequest.class,true); + api(sb,indent,HttpMethods.DELETE,AUTHZ_DELG,DelgRequest.class,false); + api(sb,indent,HttpMethods.PUT,AUTHZ_DELG,DelgRequest.class,false); + } + +} diff --git a/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/user/List.java b/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/user/List.java new file mode 100644 index 00000000..5c87f906 --- /dev/null +++ b/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/user/List.java @@ -0,0 +1,121 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.cmd.user; + +import java.util.Collections; +import java.util.Comparator; + +import org.onap.aaf.auth.cmd.BaseCmd; +import org.onap.aaf.misc.env.util.Chrono; + +import aaf.v2_0.Approval; +import aaf.v2_0.Approvals; +import aaf.v2_0.Delg; +import aaf.v2_0.Delgs; +import aaf.v2_0.Users; + +public class List extends BaseCmd { + + public List(User parent) { + super(parent,"list"); + cmds.add(new ListForRoles(this)); + cmds.add(new ListForPermission(this)); + cmds.add(new ListForCreds(this)); + cmds.add(new ListDelegates(this)); + cmds.add(new ListApprovals(this)); + cmds.add(new ListActivity(this)); + } + + + void report(Users users, boolean count, String ... str) { + reportHead(str); + int idx = 0; + java.util.List sorted = users.getUser(); + Collections.sort(sorted, new Comparator() { + @Override + public int compare(aaf.v2_0.Users.User u1, aaf.v2_0.Users.User u2) { + if(u2==null || u2 == null) { + return -1; + } + return u1.getId().compareTo(u2.getId()); + } + }); + String format = reportColHead("%-40s %-10s %-30s\n","User","Type","Expires"); + String date = "XXXX-XX-XX"; + for(aaf.v2_0.Users.User user : sorted) { + if(!aafcli.isTest()) { + date = Chrono.dateOnlyStamp(user.getExpires()); + } + pw().format(format, + count? (Integer.valueOf(++idx) + ") " + user.getId()): user.getId(), + org.onap.aaf.auth.cmd.ns.List.getType(user), + date); + } + pw().println(); + } + + public void report(Approvals approvals, String title, String id) { + reportHead(title,id); + String format = reportColHead(" %-20s %-20s %-11s %-6s %12s\n","User","Approver","Type","Status","Updated"); + java.util.List lapp = approvals.getApprovals(); + Collections.sort(lapp, new Comparator() { + @Override + public int compare(Approval a1, Approval a2) { + return a1.getTicket().compareTo(a2.getTicket()); + } + } ); + String ticket = null, prev = null; + for(Approval app : lapp ) { + ticket = app.getTicket(); + if(!ticket.equals(prev)) { + pw().print("Ticket: "); + pw().println(ticket); + } + prev = ticket; + + pw().format(format, + app.getUser(), + app.getApprover(), + app.getType(), + app.getStatus(), + Chrono.niceDateStamp(app.getUpdated()) + ); + } + } + + public void report(Delgs delgs, String title, String id) { + reportHead(title,id); + String format = reportColHead(" %-25s %-25s %-10s\n","User","Delegate","Expires"); + String date = "XXXX-XX-XX"; + for(Delg delg : delgs.getDelgs()) { + if(!this.aafcli.isTest()) + date = Chrono.dateOnlyStamp(delg.getExpires()); + pw().printf(format, + delg.getUser(), + delg.getDelegate(), + date + ); + } + } + + +} diff --git a/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/user/ListActivity.java b/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/user/ListActivity.java new file mode 100644 index 00000000..8ffcb0b6 --- /dev/null +++ b/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/user/ListActivity.java @@ -0,0 +1,78 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.cmd.user; + +import org.onap.aaf.auth.cmd.AAFcli; +import org.onap.aaf.auth.cmd.Cmd; +import org.onap.aaf.auth.cmd.Param; +import org.onap.aaf.auth.rserv.HttpMethods; +import org.onap.aaf.cadi.CadiException; +import org.onap.aaf.cadi.LocatorException; +import org.onap.aaf.cadi.client.Future; +import org.onap.aaf.cadi.client.Rcli; +import org.onap.aaf.cadi.client.Retryable; +import org.onap.aaf.misc.env.APIException; + +import aaf.v2_0.History; + +/** + * * @author Jonathan + * + */ +public class ListActivity extends Cmd { + private static final String HEADER = "List Activity of User"; + + public ListActivity(List parent) { + super(parent,"activity", + new Param("user",true)); + } + + @Override + public int _exec(int _idx, final String ... args) throws CadiException, APIException, LocatorException { + int idx = _idx; + final String user = fullID(args[idx++]); + return same(new Retryable() { + @Override + public Integer code(Rcli client) throws CadiException, APIException { + + Future fp = client.read( + "/authz/hist/user/"+user, + getDF(History.class) + ); + if(fp.get(AAFcli.timeout())) { + activity(fp.value,HEADER + " [ " + user + " ]"); + } else { + error(fp); + } + return fp.code(); + } + }); + } + + + @Override + public void detailedHelp(int indent, StringBuilder sb) { + detailLine(sb,indent,HEADER); + api(sb,indent,HttpMethods.GET,"authz/hist/user/",History.class,true); + } + +} diff --git a/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/user/ListApprovals.java b/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/user/ListApprovals.java new file mode 100644 index 00000000..0a461c49 --- /dev/null +++ b/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/user/ListApprovals.java @@ -0,0 +1,102 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.cmd.user; + +import org.onap.aaf.auth.cmd.AAFcli; +import org.onap.aaf.auth.cmd.Cmd; +import org.onap.aaf.auth.cmd.Param; +import org.onap.aaf.auth.rserv.HttpMethods; +import org.onap.aaf.cadi.CadiException; +import org.onap.aaf.cadi.LocatorException; +import org.onap.aaf.cadi.client.Future; +import org.onap.aaf.cadi.client.Rcli; +import org.onap.aaf.cadi.client.Retryable; +import org.onap.aaf.misc.env.APIException; + +import aaf.v2_0.Approvals; + +/** + * + * @author Jonathan + * + */ +public class ListApprovals extends Cmd { + private static final String HEADER = "List Approvals"; + private final static String[] options = {"user","approver","ticket"}; + public ListApprovals(List parent) { + super(parent,"approvals", + new Param(optionsToString(options),true), + new Param("value",true)); + } + + @Override + public int _exec(int _idx, final String ... args) throws CadiException, APIException, LocatorException { + int idx = _idx; + final String type = args[idx++]; + int option = whichOption(options,type); + String value = args[idx++]; + final String fullValue; + if (option != 2) { + fullValue = fullID(value); + } else { + fullValue = value; + } + return same(new Retryable() { + @Override + public Integer code(Rcli client) throws CadiException, APIException { + Future fp = client.read( + "/authz/approval/"+type+'/'+fullValue, + getDF(Approvals.class) + ); + if(fp.get(AAFcli.timeout())) { + ((List)parent).report(fp.value,HEADER + " by " + type,fullValue); + if(fp.code()==404) { + return 200; + } + } else { + error(fp); + } + return fp.code(); + } + }); + } + + @Override + public void detailedHelp(int _indent, StringBuilder sb) { + int indent = _indent; + detailLine(sb,indent,HEADER); + indent+=2; + detailLine(sb,indent,"Approvals are used when the Requestor does not have the rights"); + detailLine(sb,indent,"to perform the action required. Approvers are those listed as"); + detailLine(sb,indent,"responsible for Namespace associated with the request, and those"); + detailLine(sb,indent,"required by the Company by Policy. This may be, for instance"); + detailLine(sb,indent,"the supervisor of the requestor"); + sb.append('\n'); + detailLine(sb,indent,"Delegates can be listed by User, Approver or Ticket."); + indent-=2; + api(sb,indent,HttpMethods.GET,"authz/approval/user/",Approvals.class,true); + api(sb,indent,HttpMethods.GET,"authz/approval/approver/",Approvals.class,false); + api(sb,indent,HttpMethods.GET,"authz/approval/ticket/",Approvals.class,false); + } + + +} diff --git a/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/user/ListDelegates.java b/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/user/ListDelegates.java new file mode 100644 index 00000000..4397b426 --- /dev/null +++ b/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/user/ListDelegates.java @@ -0,0 +1,92 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.cmd.user; + +import org.onap.aaf.auth.cmd.AAFcli; +import org.onap.aaf.auth.cmd.Cmd; +import org.onap.aaf.auth.cmd.Param; +import org.onap.aaf.auth.rserv.HttpMethods; +import org.onap.aaf.cadi.CadiException; +import org.onap.aaf.cadi.LocatorException; +import org.onap.aaf.cadi.client.Future; +import org.onap.aaf.cadi.client.Rcli; +import org.onap.aaf.cadi.client.Retryable; +import org.onap.aaf.misc.env.APIException; + +import aaf.v2_0.Delgs; + +/** + * * @author Jonathan + * + */ +public class ListDelegates extends Cmd { + private static final String HEADER = "List Delegates"; + private static final String[] options = {"user","delegate"}; + public ListDelegates(List parent) { + super(parent,"delegates", + new Param(optionsToString(options),true), + new Param("id",true)); + } + + @Override + public int _exec(int _idx, final String ... args) throws CadiException, APIException, LocatorException { + int idx = _idx; + final String key = args[idx++]; + //int option = whichOption(options,key); + final String id = fullID(args[idx++]); + return same(new Retryable() { + @Override + public Integer code(Rcli client) throws CadiException, APIException { + + Future fp = client.read( + "/authz/delegates/" + key + '/' + id, + getDF(Delgs.class) + ); + if(fp.get(AAFcli.timeout())) { + ((List)parent).report(fp.value,HEADER + " by " + key, id); + if(fp.code()==404)return 200; + } else { + error(fp); + } + return fp.code(); + } + }); + } + + @Override + public void detailedHelp(int _indent, StringBuilder sb) { + int indent = _indent; + detailLine(sb,indent,HEADER); + indent+=2; + detailLine(sb,indent,"Delegates are those people temporarily assigned to cover the"); + detailLine(sb,indent,"responsibility of Approving, etc, while the actual Responsible"); + detailLine(sb,indent,"Party is absent. Typically, this is for Vacation, or Business"); + detailLine(sb,indent,"Travel."); + sb.append('\n'); + detailLine(sb,indent,"Delegates can be listed by the User or by the Delegate"); + indent-=2; + api(sb,indent,HttpMethods.GET,"authz/delegates/user/",Delgs.class,true); + api(sb,indent,HttpMethods.GET,"authz/delegates/delegate/",Delgs.class,false); + } + + +} diff --git a/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/user/ListForCreds.java b/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/user/ListForCreds.java new file mode 100644 index 00000000..4aa42f9f --- /dev/null +++ b/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/user/ListForCreds.java @@ -0,0 +1,100 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.cmd.user; + +import java.util.Collections; +import java.util.Comparator; + +import org.onap.aaf.auth.cmd.AAFcli; +import org.onap.aaf.auth.cmd.Cmd; +import org.onap.aaf.auth.cmd.Param; +import org.onap.aaf.auth.rserv.HttpMethods; +import org.onap.aaf.cadi.CadiException; +import org.onap.aaf.cadi.LocatorException; +import org.onap.aaf.cadi.client.Future; +import org.onap.aaf.cadi.client.Rcli; +import org.onap.aaf.cadi.client.Retryable; +import org.onap.aaf.misc.env.APIException; + +import aaf.v2_0.Users; +import aaf.v2_0.Users.User; + +/** + * List for Creds + * @author Jonathan + * + */ +public class ListForCreds extends Cmd { + private final static String[] options = {"ns","id"}; + + private static final String HEADER = "List creds by Namespace or ID "; + public ListForCreds(List parent) { + super(parent,"cred", + new Param(optionsToString(options),true), + new Param("value",true)); + } + + @Override + public int _exec(int _idx, final String ... args) throws CadiException, APIException, LocatorException { + int idx = _idx; + final int option = whichOption(options, args[idx++]); + final String which = options[option]; + final String value = args[idx++]; + return same(new Retryable() { + @Override + public Integer code(Rcli client) throws CadiException, APIException { + Future fp = client.read( + "/authn/creds/"+which+'/'+value, + getDF(Users.class) + ); + if(fp.get(AAFcli.timeout())) { + if (aafcli.isTest()) + Collections.sort(fp.value.getUser(), new Comparator() { + @Override + public int compare(User u1, User u2) { + return u1.getId().compareTo(u2.getId()); + } + }); + ((org.onap.aaf.auth.cmd.user.List)parent).report(fp.value,option==1,HEADER+which,value); + if(fp.code()==404)return 200; + } else { + error(fp); + } + return fp.code(); + } + }); + } + + @Override + public void detailedHelp(int _indent, StringBuilder sb) { + int indent = _indent; + detailLine(sb,indent,HEADER); + indent+=2; + detailLine(sb,indent,"This report lists the users associated to either Namespaces or IDs."); + detailLine(sb,indent,"ns (literal) - which Namespace"); + detailLine(sb,indent,"id (literal) - identity"); + indent-=2; + api(sb,indent,HttpMethods.GET,"authn/creds/ns/",Users.class,true); + api(sb,indent,HttpMethods.GET,"authn/creds/id/",Users.class,true); + } + +} diff --git a/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/user/ListForPermission.java b/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/user/ListForPermission.java new file mode 100644 index 00000000..32938101 --- /dev/null +++ b/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/user/ListForPermission.java @@ -0,0 +1,103 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.cmd.user; + +import java.util.Collections; +import java.util.Comparator; + +import org.onap.aaf.auth.cmd.AAFcli; +import org.onap.aaf.auth.cmd.Cmd; +import org.onap.aaf.auth.cmd.Param; +import org.onap.aaf.auth.rserv.HttpMethods; +import org.onap.aaf.cadi.CadiException; +import org.onap.aaf.cadi.LocatorException; +import org.onap.aaf.cadi.client.Future; +import org.onap.aaf.cadi.client.Rcli; +import org.onap.aaf.cadi.client.Retryable; +import org.onap.aaf.misc.env.APIException; + +import aaf.v2_0.Users; +import aaf.v2_0.Users.User; + +/** + * p + * @author Jonathan + * + */ +public class ListForPermission extends Cmd { + private static final String HEADER = "List Users for Permission"; + public ListForPermission(List parent) { + super(parent,"perm", + new Param("type",true), + new Param("instance",true), + new Param("action",true)); + } + + @Override + public int _exec(final int index, final String ... args) throws CadiException, APIException, LocatorException { + return same(new Retryable() { + @Override + public Integer code(Rcli client) throws CadiException, APIException { + int idx = index; + String type = args[idx++]; + String instance = args[idx++]; + if("\\*".equals(instance))instance="*"; + String action = args[idx++]; + if("\\*".equals(action))action="*"; + Future fp = client.read( + "/authz/users/perm/"+type+'/'+instance+'/'+action, + getDF(Users.class) + ); + if(fp.get(AAFcli.timeout())) { + if (aafcli.isTest()) + Collections.sort(fp.value.getUser(), new Comparator() { + @Override + public int compare(User u1, User u2) { + return u1.getId().compareTo(u2.getId()); + } + }); + ((org.onap.aaf.auth.cmd.user.List)parent).report(fp.value,false,HEADER,type+"|"+instance+"|"+action); + if(fp.code()==404)return 200; + } else { + error(fp); + } + return fp.code(); + } + }); + } + + @Override + public void detailedHelp(int _indent, StringBuilder sb) { + int indent = _indent; + detailLine(sb,indent,HEADER); + indent+=2; + detailLine(sb,indent,"This report lists the users associated to Permissions. Since Users"); + detailLine(sb,indent,"are associated to Roles, and Roles have Permissions, this report"); + detailLine(sb,indent,"accomodates all these linkages."); + sb.append('\n'); + detailLine(sb,indent,"The URL must contain the Permission's type,instance and action, and "); + detailLine(sb,indent,"may include \"*\"s (type in as \\\\*)."); + detailLine(sb,indent,"See Perm Create Documentation for definitions."); + indent-=2; + api(sb,indent,HttpMethods.GET,"authz/users/perm///",Users.class,true); + } +} diff --git a/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/user/ListForRoles.java b/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/user/ListForRoles.java new file mode 100644 index 00000000..28d7f57a --- /dev/null +++ b/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/user/ListForRoles.java @@ -0,0 +1,92 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.cmd.user; + +import java.util.Collections; +import java.util.Comparator; + +import org.onap.aaf.auth.cmd.AAFcli; +import org.onap.aaf.auth.cmd.Cmd; +import org.onap.aaf.auth.cmd.Param; +import org.onap.aaf.auth.rserv.HttpMethods; +import org.onap.aaf.cadi.CadiException; +import org.onap.aaf.cadi.LocatorException; +import org.onap.aaf.cadi.client.Future; +import org.onap.aaf.cadi.client.Rcli; +import org.onap.aaf.cadi.client.Retryable; +import org.onap.aaf.misc.env.APIException; + +import aaf.v2_0.Users; +import aaf.v2_0.Users.User; + +/** + * p + * @author Jonathan + * + */ +public class ListForRoles extends Cmd { + private static final String HEADER = "List Users for Role"; + public ListForRoles(List parent) { + super(parent,"role", new Param("role",true)); + } + + @Override + public int _exec(int _idx, final String ... args) throws CadiException, APIException, LocatorException { + int idx = _idx; + final String role = args[idx++]; + return same(new Retryable() { + @Override + public Integer code(Rcli client) throws CadiException, APIException { + Future fp = client.read( + "/authz/users/role/"+role, + getDF(Users.class) + ); + if(fp.get(AAFcli.timeout())) { + if (aafcli.isTest()) + Collections.sort(fp.value.getUser(), new Comparator() { + @Override + public int compare(User u1, User u2) { + return u1.getId().compareTo(u2.getId()); + } + }); + ((org.onap.aaf.auth.cmd.user.List)parent).report(fp.value,false, HEADER,role); + if(fp.code()==404)return 200; + } else { + error(fp); + } + return fp.code(); + } + }); + } + + @Override + public void detailedHelp(int _indent, StringBuilder sb) { + int indent = _indent; + detailLine(sb,indent,HEADER); + indent+=2; + detailLine(sb,indent,"This report lists the users associated to Roles."); + detailLine(sb,indent,"role - the Role name"); + indent-=2; + api(sb,indent,HttpMethods.GET,"authz/users/role/",Users.class,true); + } + +} diff --git a/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/user/Role.java b/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/user/Role.java new file mode 100644 index 00000000..70bc16a3 --- /dev/null +++ b/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/user/Role.java @@ -0,0 +1,155 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.cmd.user; + +import org.onap.aaf.auth.cmd.AAFcli; +import org.onap.aaf.auth.cmd.Cmd; +import org.onap.aaf.auth.cmd.Param; +import org.onap.aaf.auth.rserv.HttpMethods; +import org.onap.aaf.cadi.CadiException; +import org.onap.aaf.cadi.LocatorException; +import org.onap.aaf.cadi.client.Future; +import org.onap.aaf.cadi.client.Rcli; +import org.onap.aaf.cadi.client.Retryable; +import org.onap.aaf.misc.env.APIException; + +import aaf.v2_0.UserRoleRequest; + +/** + * p + * + * @author Jonathan + * + */ +public class Role extends Cmd { + private static final String[] options = {"add", "del", "setTo","extend"}; + public Role(User parent) { + super(parent, "role", new Param(optionsToString(options), true), new Param("user", true), new Param( + "role[,role]* (!REQ S)", false)); + } + + @Override + public int _exec(final int index, final String ... args) throws CadiException, APIException, LocatorException { + return same(new Retryable() { + @Override + public Integer code(Rcli client) throws CadiException, APIException { + int idx = index; + String key = args[idx++]; + int option = whichOption(options, key); + final String user = fullID(args[idx++]); + + UserRoleRequest urr = new UserRoleRequest(); + urr.setUser(user); + // Set Start/End commands + setStartEnd(urr); + + Future fp = null; + + if (option != 2) { + if (args.length < 5) { + throw new CadiException(build(new StringBuilder("Too few args: "), null).toString()); + } + String[] roles = args[idx++].split(","); + for (String role : roles) { + String verb = null,participle=null; + urr.setRole(role); + // You can request to be added or removed from role. + setQueryParamsOn(client); + switch(option) { + case 0: + fp = client.create("/authz/userRole", getDF(UserRoleRequest.class), urr); + verb = "Added"; + participle = "] to User [" ; + break; + case 1: + fp = client.delete("/authz/userRole/" + urr.getUser() + '/' + urr.getRole(), Void.class); + verb = "Removed"; + participle = "] from User [" ; + break; + case 3: + fp = client.update("/authz/userRole/extend/" + urr.getUser() + '/' + urr.getRole()); + verb = "Extended"; + participle = "] to User [" ; + break; + default: + throw new CadiException("Invalid action [" + key + ']'); + } + if (fp.get(AAFcli.timeout())) { + pw().print(verb); + pw().print(" Role ["); + pw().print(urr.getRole()); + pw().print(participle); + pw().print(urr.getUser()); + pw().println(']'); + } else { + switch(fp.code()) { + case 202: + pw().print("UserRole "); + pw().print(option == 0 ? "Creation" : option==1?"Deletion":"Extension"); + pw().println(" Accepted, but requires Approvals before actualizing"); + break; + case 404: + if(option==3) { + pw().println("Failed with code 404: UserRole is not found, or you do not have permission to view"); + break; + } + default: + error(fp); + } + } + } + } else { + // option 2 is setTo command (an update call) + String allRoles = ""; + if (idx < args.length) + allRoles = args[idx++]; + + urr.setRole(allRoles); + fp = client.update("/authz/userRole/user", getDF(UserRoleRequest.class), urr); + if (fp.get(AAFcli.timeout())) { + pw().println("Set User's Roles to [" + allRoles + "]"); + } else { + error(fp); + } + } + return fp == null ? 0 : fp.code(); + } + }); + } + + @Override + public void detailedHelp(int indent, StringBuilder sb) { + detailLine(sb, indent, "Add OR Delete a User to/from a Role OR"); + detailLine(sb, indent, "Set a User's Roles to the roles supplied"); + detailLine(sb, indent + 2, "user - ID of User"); + detailLine(sb, indent + 2, "role(s) - Role or Roles to which to add the User"); + sb.append('\n'); + detailLine(sb, indent + 2, "Note: this is the same as \"role user add...\" except allows"); + detailLine(sb, indent + 2, "assignment of user to multiple roles"); + detailLine(sb, indent + 2, "WARNING: Roles supplied with setTo will be the ONLY roles attached to this user"); + detailLine(sb, indent + 2, "If no roles are supplied, user's roles are reset."); + api(sb, indent, HttpMethods.POST, "authz/userRole", UserRoleRequest.class, true); + api(sb, indent, HttpMethods.DELETE, "authz/userRole//", Void.class, false); + api(sb, indent, HttpMethods.PUT, "authz/userRole/", UserRoleRequest.class, false); + } + +} diff --git a/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/user/User.java b/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/user/User.java new file mode 100644 index 00000000..458fc33a --- /dev/null +++ b/auth/auth-cmd/src/main/java/org/onap/aaf/auth/cmd/user/User.java @@ -0,0 +1,36 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.cmd.user; + +import org.onap.aaf.auth.cmd.AAFcli; +import org.onap.aaf.auth.cmd.BaseCmd; +import org.onap.aaf.misc.env.APIException; + +public class User extends BaseCmd { + public User(AAFcli aafcli) throws APIException { + super(aafcli,"user"); + cmds.add(new Role(this)); + cmds.add(new Cred(this)); + cmds.add(new Delg(this)); + cmds.add(new List(this)); + } +} diff --git a/auth/auth-cmd/src/test/java/org/onap/aaf/auth/cmd/test/JU_AAFCli.java b/auth/auth-cmd/src/test/java/org/onap/aaf/auth/cmd/test/JU_AAFCli.java new file mode 100644 index 00000000..d0013fef --- /dev/null +++ b/auth/auth-cmd/src/test/java/org/onap/aaf/auth/cmd/test/JU_AAFCli.java @@ -0,0 +1,198 @@ +/******************************************************************************* + * ============LICENSE_START==================================================== + * * org.onap.aaf + * * =========================================================================== + * * Copyright © 2017 AT&T Intellectual Property. All rights reserved. + * * =========================================================================== + * * 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==================================================== + * * + * * + ******************************************************************************/ +package org.onap.aaf.auth.cmd.test; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; +import static org.mockito.Mockito.mock; + +import java.io.IOException; +import java.io.OutputStreamWriter; +import java.net.HttpURLConnection; +import java.security.GeneralSecurityException; + +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.runners.MockitoJUnitRunner; +import org.onap.aaf.auth.cmd.AAFcli; +import org.onap.aaf.auth.env.AuthzEnv; +import org.onap.aaf.cadi.CadiException; +import org.onap.aaf.cadi.Locator; +import org.onap.aaf.cadi.LocatorException; +import org.onap.aaf.cadi.config.Config; +import org.onap.aaf.cadi.config.SecurityInfo; +import org.onap.aaf.cadi.http.HBasicAuthSS; +import org.onap.aaf.cadi.http.HMangr; +import org.onap.aaf.cadi.locator.PropertyLocator; +import org.onap.aaf.misc.env.APIException; +@RunWith(MockitoJUnitRunner.class) +public class JU_AAFCli { + + private static AAFcli cli; + private static int TIMEOUT = Integer.parseInt(Config.AAF_CONN_TIMEOUT_DEF); + +// @BeforeClass +// public static void setUp() throws Exception, Exception { +// cli = getAAfCli(); +// } +// +// @Test +// public void eval() throws Exception { +// assertTrue(cli.eval("#startswith")); +// } +// +// @Test +// public void eval_empty() throws Exception { +// assertTrue(cli.eval("")); +// } +// +// @Test +// public void eval1() throws Exception { +// assertTrue(cli.eval("@[123")); +// } +// +// @Test +// public void eval2() throws Exception { +// assertFalse(cli.eval("as @[ 123")); +// } +// +// @Test +// public void eval3() throws Exception { +// try { +// cli.eval("expect @[ 123"); +// } catch (Exception e) { +// // TODO Auto-generated catch block +// assertTrue(e instanceof CadiException); +// } +// } +// +// public void eval31() throws Exception { +// try { +// cli.eval("expect 1 @[ 123"); +// } catch (Exception e) { +// // TODO Auto-generated catch block +// assertTrue(e instanceof CadiException); +// } +// } +// +// @Test +// public void eval4() throws Exception { +// try { +// cli.eval("sleep @[ 123"); +// } catch (Exception e) { +// assertTrue(e instanceof NumberFormatException); +// } +// } +// +// @Test +// public void eval41() throws Exception { +// assertTrue(cli.eval("sleep 1 @[ 123")); +// } +// +// @Test +// public void eval5() throws Exception { +// try { +// cli.eval("delay @[ 123"); +// } catch (Exception e) { +// assertTrue(e instanceof NumberFormatException); +// } +// } +// +// @Test +// public void eval51() throws Exception { +// assertTrue(cli.eval("delay 1 @[ 123")); +// } +// +// @Test +// public void eval7() throws Exception { +// assertFalse(cli.eval("exit @[ 123")); +// } +// +// @Test +// public void eval8() throws Exception { +// assertTrue(cli.eval("REQUEST @[ 123")); +// } +// +// @Test +// public void eval9() throws Exception { +// assertTrue(cli.eval("FORCE @[ 123")); +// } +// +// @Test +// public void eval10() throws Exception { +// assertTrue(cli.eval("set @[ 123")); +// } +// +// @Test +// public void keyboardHelp() throws Exception { +// boolean noError=true; +// try { +// cli.keyboardHelp(); +// } catch (Exception e) { +// noError=false; +// } +// assertTrue(noError); +// } +// +// +// +// @Test +// public void setProp() throws Exception { +// boolean noError=true; +// try { +// cli.keyboardHelp(); +// } catch (Exception e) { +// noError=false; +// } +// assertTrue(noError); +// } +// +// @Test +// public void eval_randomString() throws Exception { +// assertTrue(cli.eval("Some random string @#&*& to check complete 100 coverage")); +// } + +// public static AAFcli getAAfCli() throws APIException, LocatorException, GeneralSecurityException, IOException { +// final AuthzEnv env = new AuthzEnv(System.getProperties()); +// String aafUrl = "https://DME2RESOLVE"; +// SecurityInfo si = new SecurityInfo(env); +// env.loadToSystemPropsStartsWith("AAF", "DME2"); +// Locator loc; +// loc = new PropertyLocator(aafUrl); +// TIMEOUT = Integer.parseInt(env.getProperty(Config.AAF_CONN_TIMEOUT, Config.AAF_CONN_TIMEOUT_DEF)); +// HMangr hman = new HMangr(env, loc).readTimeout(TIMEOUT).apiVersion("2.0"); +// +// // TODO: Consider requiring a default in properties +// env.setProperty(Config.AAF_DEFAULT_REALM, +// System.getProperty(Config.AAF_DEFAULT_REALM, Config.getDefaultRealm())); +// HBasicAuthSS ss = mock(HBasicAuthSS.class); +// //TODO: Gabe[JUnit] constructor issue +// return new AAFcli(env, new OutputStreamWriter(System.out), hman, si, ss); +// } + + @Test //TODO: Temporary fix AAF-111 + public void netYetTested() { + fail("Tests not yet implemented"); + } +} diff --git a/auth/auth-cmd/src/test/java/org/onap/aaf/auth/cmd/test/JU_BaseCmd.java b/auth/auth-cmd/src/test/java/org/onap/aaf/auth/cmd/test/JU_BaseCmd.java new file mode 100644 index 00000000..75ae8160 --- /dev/null +++ b/auth/auth-cmd/src/test/java/org/onap/aaf/auth/cmd/test/JU_BaseCmd.java @@ -0,0 +1,243 @@ +/******************************************************************************* + * ============LICENSE_START==================================================== + * * org.onap.aaf + * * =========================================================================== + * * Copyright © 2017 AT&T Intellectual Property. All rights reserved. + * * =========================================================================== + * * 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==================================================== + * * + * * + ******************************************************************************/ +package org.onap.aaf.auth.cmd.test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; + +import java.io.IOException; +import java.security.GeneralSecurityException; +import java.util.Date; +import java.util.GregorianCalendar; + +import javax.xml.datatype.DatatypeConfigurationException; +import javax.xml.datatype.DatatypeFactory; +import javax.xml.datatype.XMLGregorianCalendar; + +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.runners.MockitoJUnitRunner; +import org.onap.aaf.auth.cmd.AAFcli; +import org.onap.aaf.auth.cmd.BaseCmd; +import org.onap.aaf.cadi.CadiException; +import org.onap.aaf.cadi.LocatorException; +import org.onap.aaf.cadi.client.Future; +import org.onap.aaf.misc.env.APIException; + +import aaf.v2_0.History; + +@RunWith(MockitoJUnitRunner.class) +public class JU_BaseCmd { + + private static AAFcli cli; + private static BaseCmd bCmd; + +// @BeforeClass +// public static void setUp() throws APIException, LocatorException, GeneralSecurityException, IOException { +// cli = JU_AAFCli.getAAfCli(); +// bCmd = new BaseCmd<>(cli, "testString"); +// } + +// @Test +// public void exec() throws CadiException, APIException, LocatorException { +// assertEquals(bCmd._exec(4, "add", "del", "reset", "extend"), 0); +// +// } +// +// @Test +// public void exec1() throws CadiException, APIException, LocatorException { +// assertEquals(bCmd._exec(0, "add", "del", "reset", "extend"), 0); +// +// } + +// @Test +// public void error() throws CadiException, APIException, LocatorException { +// boolean noError = true; +// Future future = new Future() { +// +// @Override +// public boolean get(int timeout) throws CadiException { +// // TODO Auto-generated method stub +// return false; +// } +// +// @Override +// public int code() { +// // TODO Auto-generated method stub +// return 0; +// } +// +// @Override +// public String body() { +// // TODO Auto-generated method stub +// return "{%}"; +// } +// +// @Override +// public String header(String tag) { +// // TODO Auto-generated method stub +// return null; +// } +// }; +// try { +// //TODO: Gabe [JUnit] Not visible for junit +// bCmd.error(future); +// } catch (Exception e) { +// noError = false; +// } +// assertEquals(noError, true); +// +// } +// +// +// +// @Test +// public void activity() throws DatatypeConfigurationException { +// boolean noError = true; +// History history = new History(); +// History.Item item = new History.Item(); +// item.setTarget("target"); +// item.setUser("user"); +// item.setMemo("memo"); +// +// GregorianCalendar c = new GregorianCalendar(); +// c.setTime(new Date()); +// XMLGregorianCalendar date = DatatypeFactory.newInstance().newXMLGregorianCalendar(c); +// item.setTimestamp(date); +// history.getItem().add(item); +// try { +// bCmd.activity(history, "history"); +// } catch (Exception e) { +// noError = false; +// } +// assertEquals(noError, true); +// +// } +// +// @Test +// public void activity1() throws DatatypeConfigurationException { +// boolean noError = true; +// History history = new History(); +// History.Item item = new History.Item(); +// item.setTarget("target"); +// item.setUser("user"); +// item.setMemo("memo"); +// +// GregorianCalendar c = new GregorianCalendar(); +// c.setTime(new Date()); +// XMLGregorianCalendar date = DatatypeFactory.newInstance().newXMLGregorianCalendar(c); +// item.setTimestamp(date); +// history.getItem().add(item); +// try { +// bCmd.activity(history, "1[]"); +// } catch (Exception e) { +// noError = false; +// } +// assertEquals(noError, true); +// +// } +// +// +// +// @Test +// public void error1() { +// boolean noError = true; +// Future future = new Future() { +// +// @Override +// public boolean get(int timeout) throws CadiException { +// // TODO Auto-generated method stub +// return false; +// } +// +// @Override +// public int code() { +// // TODO Auto-generated method stub +// return 0; +// } +// +// @Override +// public String body() { +// // TODO Auto-generated method stub +// return "{1"; +// } +// +// @Override +// public String header(String tag) { +// // TODO Auto-generated method stub +// return null; +// } +// }; +// try { +// bCmd.error(future); +// } catch (Exception e) { +// noError = false; +// } +// assertEquals(noError, true); +// +// } + +// @Test +// public void error2() { +// boolean noError = true; +// Future future = new Future() { +// +// @Override +// public boolean get(int timeout) throws CadiException { +// // TODO Auto-generated method stub +// return false; +// } +// +// @Override +// public int code() { +// // TODO Auto-generated method stub +// return 0; +// } +// +// @Override +// public String body() { +// // TODO Auto-generated method stub +// return "other"; +// } +// +// @Override +// public String header(String tag) { +// // TODO Auto-generated method stub +// return null; +// } +// }; +// try { +// bCmd.error(future); +// } catch (Exception e) { +// noError = false; +// } +// assertEquals(noError, true); +// +// } + + @Test //TODO: Temporary fix AAF-111 + public void netYetTested() { + fail("Tests not yet implemented"); + } + +} diff --git a/auth/auth-cmd/src/test/java/org/onap/aaf/auth/cmd/test/JU_BasicAuth.java b/auth/auth-cmd/src/test/java/org/onap/aaf/auth/cmd/test/JU_BasicAuth.java new file mode 100644 index 00000000..6e79f816 --- /dev/null +++ b/auth/auth-cmd/src/test/java/org/onap/aaf/auth/cmd/test/JU_BasicAuth.java @@ -0,0 +1,53 @@ +/******************************************************************************* + * ============LICENSE_START==================================================== + * * org.onap.aaf + * * =========================================================================== + * * Copyright © 2017 AT&T Intellectual Property. All rights reserved. + * * =========================================================================== + * * 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==================================================== + * * + * * + ******************************************************************************/ +package org.onap.aaf.auth.cmd.test; + +import static org.junit.Assert.*; + +import java.io.IOException; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.runners.MockitoJUnitRunner; +//import org.onap.aaf.auth.cmd.BasicAuth; +//TODO: Gabe [JUnit] Import missing +@RunWith(MockitoJUnitRunner.class) +public class JU_BasicAuth { + +// @Test +// public void getID () { +// try { +// BasicAuth bAuth = new BasicAuth("testUser", "nopass"); +// assertEquals(bAuth.getID(), "testUser"); +// System.out.println(bAuth.getID()); +// } catch (IOException e) { +// // TODO Auto-generated catch block +// e.printStackTrace(); +// } +// +// } + + @Test + public void netYetTested() { + fail("Tests not yet implemented"); + } +} diff --git a/auth/auth-cmd/src/test/java/org/onap/aaf/auth/cmd/test/JU_Help.java b/auth/auth-cmd/src/test/java/org/onap/aaf/auth/cmd/test/JU_Help.java new file mode 100644 index 00000000..a44804d9 --- /dev/null +++ b/auth/auth-cmd/src/test/java/org/onap/aaf/auth/cmd/test/JU_Help.java @@ -0,0 +1,97 @@ +/******************************************************************************* + * ============LICENSE_START==================================================== + * * org.onap.aaf + * * =========================================================================== + * * Copyright © 2017 AT&T Intellectual Property. All rights reserved. + * * =========================================================================== + * * 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==================================================== + * * + * * + ******************************************************************************/ +package org.onap.aaf.auth.cmd.test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; + +import java.io.IOException; +import java.security.GeneralSecurityException; +import java.util.ArrayList; +import java.util.List; + +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.runners.MockitoJUnitRunner; +import org.onap.aaf.auth.cmd.AAFcli; +import org.onap.aaf.auth.cmd.Cmd; +import org.onap.aaf.auth.cmd.Help; +import org.onap.aaf.cadi.CadiException; +import org.onap.aaf.cadi.LocatorException; +import org.onap.aaf.misc.env.APIException; + +//import com.att.aft.dme2.internal.jetty.http.HttpStatus; +//TODO: Gabe [JUnit] Import missing +@RunWith(MockitoJUnitRunner.class) +public class JU_Help { + +// private static AAFcli cli; +// private static Help help; +// +// @Mock +// private static List cmds; +// +// @BeforeClass +// public static void setUp() throws APIException, LocatorException, GeneralSecurityException, IOException { +// cli = JU_AAFCli.getAAfCli(); +// cmds = new ArrayList<>(); +// help = new Help(cli, cmds); +// } +// +// @Test +// public void exec_HTTP_200() { +// try { +// assertEquals(help._exec(1, "helps"), HttpStatus.OK_200); +// } catch (CadiException | APIException | LocatorException e) { +// // TODO Auto-generated catch block +// e.printStackTrace(); +// } +// } +// +// @Test +// public void exec_HTTP_200_1() { +// try { +// assertEquals(help._exec(1, "helps","help"), HttpStatus.OK_200); +// } catch (CadiException | APIException | LocatorException e) { +// // TODO Auto-generated catch block +// e.printStackTrace(); +// } +// } +// +// @Test +// public void detailhelp() { +// boolean hasError=false; +// try { +// help.detailedHelp(2, new StringBuilder("detail help test")); +// } catch (Exception e) { +// hasError=true; +// } +// assertEquals(hasError,false); +// } + + @Test //TODO: Temporary fix AAF-111 + public void netYetTested() { + fail("Tests not yet implemented"); + } +} diff --git a/auth/auth-cmd/src/test/java/org/onap/aaf/auth/cmd/test/JU_Version.java b/auth/auth-cmd/src/test/java/org/onap/aaf/auth/cmd/test/JU_Version.java new file mode 100644 index 00000000..dddd4944 --- /dev/null +++ b/auth/auth-cmd/src/test/java/org/onap/aaf/auth/cmd/test/JU_Version.java @@ -0,0 +1,64 @@ +/******************************************************************************* + * ============LICENSE_START==================================================== + * * org.onap.aaf + * * =========================================================================== + * * Copyright © 2017 AT&T Intellectual Property. All rights reserved. + * * =========================================================================== + * * 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==================================================== + * * + * * + ******************************************************************************/ +package org.onap.aaf.auth.cmd.test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; + +import java.io.IOException; +import java.security.GeneralSecurityException; + +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.runners.MockitoJUnitRunner; +import org.onap.aaf.auth.cmd.AAFcli; +import org.onap.aaf.auth.cmd.Version; +import org.onap.aaf.cadi.CadiException; +import org.onap.aaf.cadi.LocatorException; +import org.onap.aaf.misc.env.APIException; + +//import com.att.aft.dme2.internal.jetty.http.HttpStatus; +//TODO: Gabe [JUnit] Import missing +@RunWith(MockitoJUnitRunner.class) +public class JU_Version { + +// private static AAFcli cli; +// private static Version version; +// +// @BeforeClass +// public static void setUp() throws APIException, LocatorException, GeneralSecurityException, IOException { +// cli = JU_AAFCli.getAAfCli(); +// version = new Version(cli); +// } +// +// @Test +// public void exec_HTTP_200() throws CadiException, APIException, LocatorException { +// assertEquals(version._exec(0, "Version"), HttpStatus.OK_200); +// +// } + + @Test //TODO: Temporary fix AAF-111 + public void netYetTested() { + fail("Tests not yet implemented"); + } +} diff --git a/auth/auth-cmd/src/test/java/org/onap/aaf/auth/cmd/test/mgmt/JU_Clear.java b/auth/auth-cmd/src/test/java/org/onap/aaf/auth/cmd/test/mgmt/JU_Clear.java new file mode 100644 index 00000000..078d84e8 --- /dev/null +++ b/auth/auth-cmd/src/test/java/org/onap/aaf/auth/cmd/test/mgmt/JU_Clear.java @@ -0,0 +1,61 @@ +/******************************************************************************* + * ============LICENSE_START==================================================== + * * org.onap.aaf + * * =========================================================================== + * * Copyright © 2017 AT&T Intellectual Property. All rights reserved. + * * =========================================================================== + * * 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==================================================== + * * + * * + ******************************************************************************/ +package org.onap.aaf.auth.cmd.test.mgmt; + +import static org.mockito.Mockito.mock; +import static org.junit.Assert.assertEquals; + +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.runners.MockitoJUnitRunner; +import org.onap.aaf.auth.cmd.mgmt.Clear; +import org.onap.aaf.cadi.CadiException; +import org.onap.aaf.cadi.LocatorException; +import org.onap.aaf.misc.env.APIException; + +@RunWith(MockitoJUnitRunner.class) +public class JU_Clear { + + private static Clear clr; + + @BeforeClass + public static void setUp() { + clr = mock(Clear.class); + } + + @Test + public void exec() { + try { + assertEquals(clr._exec(0, "clear"), 0); + } catch (CadiException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (APIException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (LocatorException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } +} diff --git a/auth/auth-cmd/src/test/java/org/onap/aaf/auth/cmd/test/mgmt/JU_Log.java b/auth/auth-cmd/src/test/java/org/onap/aaf/auth/cmd/test/mgmt/JU_Log.java new file mode 100644 index 00000000..6a8a2848 --- /dev/null +++ b/auth/auth-cmd/src/test/java/org/onap/aaf/auth/cmd/test/mgmt/JU_Log.java @@ -0,0 +1,61 @@ +/******************************************************************************* + * ============LICENSE_START==================================================== + * * org.onap.aaf + * * =========================================================================== + * * Copyright © 2017 AT&T Intellectual Property. All rights reserved. + * * =========================================================================== + * * 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==================================================== + * * + * * + ******************************************************************************/ +package org.onap.aaf.auth.cmd.test.mgmt; + +import static org.mockito.Mockito.mock; +import static org.junit.Assert.assertEquals; + +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.runners.MockitoJUnitRunner; +import org.onap.aaf.auth.cmd.mgmt.Log; +import org.onap.aaf.cadi.CadiException; +import org.onap.aaf.cadi.LocatorException; +import org.onap.aaf.misc.env.APIException; + +@RunWith(MockitoJUnitRunner.class) +public class JU_Log { + + private static Log log; + + @BeforeClass + public static void setUp() { + log = mock(Log.class); + } + + @Test + public void exec() { + try { + assertEquals(log._exec(0, "session clear"), 0); + } catch (CadiException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (APIException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (LocatorException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } +} diff --git a/auth/auth-cmd/src/test/java/org/onap/aaf/auth/cmd/test/mgmt/JU_SessClear.java b/auth/auth-cmd/src/test/java/org/onap/aaf/auth/cmd/test/mgmt/JU_SessClear.java new file mode 100644 index 00000000..ca2cba61 --- /dev/null +++ b/auth/auth-cmd/src/test/java/org/onap/aaf/auth/cmd/test/mgmt/JU_SessClear.java @@ -0,0 +1,61 @@ +/******************************************************************************* + * ============LICENSE_START==================================================== + * * org.onap.aaf + * * =========================================================================== + * * Copyright © 2017 AT&T Intellectual Property. All rights reserved. + * * =========================================================================== + * * 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==================================================== + * * + * * + ******************************************************************************/ +package org.onap.aaf.auth.cmd.test.mgmt; + +import static org.mockito.Mockito.mock; +import static org.junit.Assert.assertEquals; + +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.runners.MockitoJUnitRunner; +import org.onap.aaf.auth.cmd.mgmt.SessClear; +import org.onap.aaf.cadi.CadiException; +import org.onap.aaf.cadi.LocatorException; +import org.onap.aaf.misc.env.APIException; + +@RunWith(MockitoJUnitRunner.class) +public class JU_SessClear { + + private static SessClear sessclr; + + @BeforeClass + public static void setUp() { + sessclr = mock(SessClear.class); + } + + @Test + public void exec() { + try { + assertEquals(sessclr._exec(0, "session clear"), 0); + } catch (CadiException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (APIException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (LocatorException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } +} diff --git a/auth/auth-cmd/src/test/java/org/onap/aaf/auth/cmd/test/ns/JU_Admin.java b/auth/auth-cmd/src/test/java/org/onap/aaf/auth/cmd/test/ns/JU_Admin.java new file mode 100644 index 00000000..c8b85fd3 --- /dev/null +++ b/auth/auth-cmd/src/test/java/org/onap/aaf/auth/cmd/test/ns/JU_Admin.java @@ -0,0 +1,71 @@ +/******************************************************************************* + * ============LICENSE_START==================================================== + * * org.onap.aaf + * * =========================================================================== + * * Copyright © 2017 AT&T Intellectual Property. All rights reserved. + * * =========================================================================== + * * 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==================================================== + * * + * * + ******************************************************************************/ +package org.onap.aaf.auth.cmd.test.ns; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; + +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.runners.MockitoJUnitRunner; +import org.onap.aaf.auth.cmd.AAFcli; +import org.onap.aaf.auth.cmd.ns.Admin; +import org.onap.aaf.auth.cmd.ns.NS; + +@RunWith(MockitoJUnitRunner.class) +public class JU_Admin { + +// private static Admin admin; +// +// @BeforeClass +// public static void setUp() throws NoSuchFieldException, SecurityException, Exception, IllegalAccessException { +// AAFcli cli = org.onap.aaf.auth.cmd.test.JU_AAFCli.getAAfCli(); +// NS ns = new NS(cli); +// admin = new Admin(ns); +// } +// +// @Test +// public void exec() { +// try { +// assertEquals(admin._exec(0, "add", "del", "reset", "extend"), 500); +// } catch (Exception e) { +// assertEquals(e.getMessage(), "java.net.UnknownHostException: DME2RESOLVE"); +// } +// } +// +// @Test +// public void detailedHelp() { +// boolean hasNoError = true; +// try { +// admin.detailedHelp(1, new StringBuilder("test")); +// } catch (Exception e) { +// hasNoError = false; +// } +// assertEquals(hasNoError, true); +// } + + @Test //TODO: Temporary fix AAF-111 + public void netYetTested() { + fail("Tests not yet implemented"); + } +} diff --git a/auth/auth-cmd/src/test/java/org/onap/aaf/auth/cmd/test/ns/JU_Attrib.java b/auth/auth-cmd/src/test/java/org/onap/aaf/auth/cmd/test/ns/JU_Attrib.java new file mode 100644 index 00000000..ff6a8f84 --- /dev/null +++ b/auth/auth-cmd/src/test/java/org/onap/aaf/auth/cmd/test/ns/JU_Attrib.java @@ -0,0 +1,72 @@ +/******************************************************************************* + * ============LICENSE_START==================================================== + * * org.onap.aaf + * * =========================================================================== + * * Copyright © 2017 AT&T Intellectual Property. All rights reserved. + * * =========================================================================== + * * 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==================================================== + * * + * * + ******************************************************************************/ +package org.onap.aaf.auth.cmd.test.ns; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; + +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.runners.MockitoJUnitRunner; +import org.onap.aaf.auth.cmd.AAFcli; +import org.onap.aaf.auth.cmd.ns.Attrib; +import org.onap.aaf.auth.cmd.ns.NS; +import org.onap.aaf.auth.cmd.test.JU_AAFCli; + +@RunWith(MockitoJUnitRunner.class) +public class JU_Attrib { + +// private static Attrib attrib; +// +// @BeforeClass +// public static void setUp() throws NoSuchFieldException, SecurityException, Exception, IllegalAccessException { +// AAFcli cli = JU_AAFCli.getAAfCli(); +// NS ns = new NS(cli); +// attrib = new Attrib(ns); +// } +// +// @Test +// public void exec() { +// try { +// attrib._exec(0, "add", "del", "reset", "extend"); +// } catch (Exception e) { +// assertEquals(e.getMessage(), "java.net.UnknownHostException: DME2RESOLVE"); +// } +// } +// +// @Test +// public void detailedHelp() { +// boolean hasNoError = true; +// try { +// attrib.detailedHelp(1, new StringBuilder("test")); +// } catch (Exception e) { +// hasNoError = false; +// } +// assertEquals(hasNoError, true); +// } + + @Test //TODO: Temporary fix AAF-111 + public void netYetTested() { + fail("Tests not yet implemented"); + } +} diff --git a/auth/auth-cmd/src/test/java/org/onap/aaf/auth/cmd/test/ns/JU_Create.java b/auth/auth-cmd/src/test/java/org/onap/aaf/auth/cmd/test/ns/JU_Create.java new file mode 100644 index 00000000..b0822cd1 --- /dev/null +++ b/auth/auth-cmd/src/test/java/org/onap/aaf/auth/cmd/test/ns/JU_Create.java @@ -0,0 +1,72 @@ +/******************************************************************************* + * ============LICENSE_START==================================================== + * * org.onap.aaf + * * =========================================================================== + * * Copyright © 2017 AT&T Intellectual Property. All rights reserved. + * * =========================================================================== + * * 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==================================================== + * * + * * + ******************************************************************************/ +package org.onap.aaf.auth.cmd.test.ns; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; + +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.runners.MockitoJUnitRunner; +import org.onap.aaf.auth.cmd.AAFcli; +import org.onap.aaf.auth.cmd.ns.Create; +import org.onap.aaf.auth.cmd.ns.NS; +import org.onap.aaf.auth.cmd.test.JU_AAFCli; + +@RunWith(MockitoJUnitRunner.class) +public class JU_Create { + + private static Create create;//might need to replace import with org.onap.aaf.auth.cmd.perm + +// @BeforeClass +// public static void setUp() throws NoSuchFieldException, SecurityException, Exception, IllegalAccessException { +// AAFcli cli = JU_AAFCli.getAAfCli(); +// NS ns = new NS(cli); +// create = new Create(ns); +// } + + @Test //TODO: Temporary fix AAF-111 + public void netYetTested() { + fail("Tests not yet implemented"); + } + + @Test + public void exec() { + try { + assertEquals(create._exec(0, "add", "del", "reset", "extend"), 500); + } catch (Exception e) { + assertEquals(e.getMessage(), "java.net.UnknownHostException: DME2RESOLVE"); + } + } + + @Test + public void detailedHelp() { + boolean hasNoError = true; + try { + create.detailedHelp(1, new StringBuilder("test")); + } catch (Exception e) { + hasNoError = false; + } + assertEquals(hasNoError, true); + } +} diff --git a/auth/auth-cmd/src/test/java/org/onap/aaf/auth/cmd/test/ns/JU_Delete.java b/auth/auth-cmd/src/test/java/org/onap/aaf/auth/cmd/test/ns/JU_Delete.java new file mode 100644 index 00000000..fecca0b0 --- /dev/null +++ b/auth/auth-cmd/src/test/java/org/onap/aaf/auth/cmd/test/ns/JU_Delete.java @@ -0,0 +1,76 @@ +/******************************************************************************* + * ============LICENSE_START==================================================== + * * org.onap.aaf + * * =========================================================================== + * * Copyright © 2017 AT&T Intellectual Property. All rights reserved. + * * =========================================================================== + * * 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==================================================== + * * + * * + ******************************************************************************/ +package org.onap.aaf.auth.cmd.test.ns; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; + +import java.io.IOException; +import java.security.GeneralSecurityException; + +import org.junit.BeforeClass; +import org.junit.Test; +import org.onap.aaf.auth.cmd.AAFcli; +import org.onap.aaf.auth.cmd.ns.Delete; +import org.onap.aaf.auth.cmd.ns.NS; +import org.onap.aaf.auth.cmd.test.JU_AAFCli; +import org.onap.aaf.cadi.LocatorException; +import org.onap.aaf.misc.env.APIException; + +public class JU_Delete { + +// private static Delete delete;//import may be org.onap.aaf.auth.cmd.perm +// +// @BeforeClass +// public static void setUp() throws APIException, LocatorException, GeneralSecurityException, IOException { +// AAFcli cli = JU_AAFCli.getAAfCli(); +// NS ns = new NS(cli); +// delete = new Delete(ns); +// +// } +// +// @Test +// public void exec() { +// try { +// delete._exec(0, "del", "del", "del"); +// } catch (Exception e) { +// assertEquals(e.getMessage(), "java.net.UnknownHostException: DME2RESOLVE"); +// } +// } +// +// @Test +// public void detailedHelp() { +// boolean hasNoError = true; +// try { +// delete.detailedHelp(1, new StringBuilder("test")); +// } catch (Exception e) { +// hasNoError = false; +// } +// assertEquals(hasNoError, true); +// } + + @Test //TODO: Temporary fix AAF-111 + public void netYetTested() { + fail("Tests not yet implemented"); + } + +} diff --git a/auth/auth-cmd/src/test/java/org/onap/aaf/auth/cmd/test/ns/JU_Describe.java b/auth/auth-cmd/src/test/java/org/onap/aaf/auth/cmd/test/ns/JU_Describe.java new file mode 100644 index 00000000..4d4deb1b --- /dev/null +++ b/auth/auth-cmd/src/test/java/org/onap/aaf/auth/cmd/test/ns/JU_Describe.java @@ -0,0 +1,77 @@ +/******************************************************************************* + * ============LICENSE_START==================================================== + * * org.onap.aaf + * * =========================================================================== + * * Copyright © 2017 AT&T Intellectual Property. All rights reserved. + * * =========================================================================== + * * 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==================================================== + * * + * * + ******************************************************************************/ +package org.onap.aaf.auth.cmd.test.ns; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; +import static org.mockito.Mockito.CALLS_REAL_METHODS; +import static org.mockito.Mockito.mock; + +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; + +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.runners.MockitoJUnitRunner; +import org.onap.aaf.auth.cmd.AAFcli; +import org.onap.aaf.auth.cmd.ns.Describe; +import org.onap.aaf.auth.cmd.ns.NS; +import org.onap.aaf.auth.cmd.test.JU_AAFCli; +import org.onap.aaf.cadi.CadiException; +import org.onap.aaf.cadi.LocatorException; +import org.onap.aaf.misc.env.APIException; + +@RunWith(MockitoJUnitRunner.class) +public class JU_Describe { + +// private static Describe desc; +// +// @BeforeClass +// public static void setUp () throws NoSuchFieldException, SecurityException, Exception, IllegalAccessException { +// AAFcli cli = JU_AAFCli.getAAfCli(); +// NS ns = new NS(cli); +// desc = new Describe(ns); +// } +// +// @Test +// public void exec() { +// try { +// assertEquals(desc._exec(0, "add","del","reset","extend"),500); +// } catch (CadiException e) { +// // TODO Auto-generated catch block +// e.printStackTrace(); +// } catch (APIException e) { +// // TODO Auto-generated catch block +// e.printStackTrace(); +// } catch (LocatorException e) { +// // TODO Auto-generated catch block +// e.printStackTrace(); +// } +// } + + @Test //TODO: Temporary fix AAF-111 + public void netYetTested() { + fail("Tests not yet implemented"); + } +} + diff --git a/auth/auth-cmd/src/test/java/org/onap/aaf/auth/cmd/test/ns/JU_ListActivity.java b/auth/auth-cmd/src/test/java/org/onap/aaf/auth/cmd/test/ns/JU_ListActivity.java new file mode 100644 index 00000000..64328887 --- /dev/null +++ b/auth/auth-cmd/src/test/java/org/onap/aaf/auth/cmd/test/ns/JU_ListActivity.java @@ -0,0 +1,74 @@ +/******************************************************************************* + * ============LICENSE_START==================================================== + * * org.onap.aaf + * * =========================================================================== + * * Copyright © 2017 AT&T Intellectual Property. All rights reserved. + * * =========================================================================== + * * 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==================================================== + * * + * * + ******************************************************************************/ +package org.onap.aaf.auth.cmd.test.ns; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; + +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.runners.MockitoJUnitRunner; +import org.onap.aaf.auth.cmd.AAFcli; +import org.onap.aaf.auth.cmd.ns.List; +import org.onap.aaf.auth.cmd.ns.ListActivity; +import org.onap.aaf.auth.cmd.ns.NS; +import org.onap.aaf.auth.cmd.test.JU_AAFCli; +import org.onap.aaf.cadi.CadiException; +import org.onap.aaf.cadi.LocatorException; +import org.onap.aaf.misc.env.APIException; + +@RunWith(MockitoJUnitRunner.class) +public class JU_ListActivity { + +// private static ListActivity lsActivity; +// +// @BeforeClass +// public static void setUp () throws NoSuchFieldException, SecurityException, Exception, IllegalAccessException { +// AAFcli cli = JU_AAFCli.getAAfCli(); +// NS ns = new NS(cli); +// List ls = new List(ns); +// lsActivity = new ListActivity(ls); +// } +// +// @Test +// public void exec() { +// try { +// assertEquals(lsActivity._exec(0, "add","del","reset","extend"),500); +// } catch (CadiException e) { +// // TODO Auto-generated catch block +// e.printStackTrace(); +// } catch (APIException e) { +// // TODO Auto-generated catch block +// e.printStackTrace(); +// } catch (LocatorException e) { +// // TODO Auto-generated catch block +// e.printStackTrace(); +// } +// } + + @Test //TODO: Temporary fix AAF-111 + public void netYetTested() { + fail("Tests not yet implemented"); + } +} + diff --git a/auth/auth-cmd/src/test/java/org/onap/aaf/auth/cmd/test/ns/JU_ListAdminResponsible.java b/auth/auth-cmd/src/test/java/org/onap/aaf/auth/cmd/test/ns/JU_ListAdminResponsible.java new file mode 100644 index 00000000..064bade2 --- /dev/null +++ b/auth/auth-cmd/src/test/java/org/onap/aaf/auth/cmd/test/ns/JU_ListAdminResponsible.java @@ -0,0 +1,75 @@ +/******************************************************************************* + * ============LICENSE_START==================================================== + * * org.onap.aaf + * * =========================================================================== + * * Copyright © 2017 AT&T Intellectual Property. All rights reserved. + * * =========================================================================== + * * 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==================================================== + * * + * * + ******************************************************************************/ +package org.onap.aaf.auth.cmd.test.ns; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; + +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.runners.MockitoJUnitRunner; +import org.onap.aaf.auth.cmd.AAFcli; +import org.onap.aaf.auth.cmd.ns.List; +import org.onap.aaf.auth.cmd.ns.ListAdminResponsible; +import org.onap.aaf.auth.cmd.ns.NS; +import org.onap.aaf.auth.cmd.test.JU_AAFCli; +import org.onap.aaf.cadi.CadiException; +import org.onap.aaf.cadi.LocatorException; +import org.onap.aaf.misc.env.APIException; + +@RunWith(MockitoJUnitRunner.class) +public class JU_ListAdminResponsible { + +// private static ListAdminResponsible lsAdminRes; +// +// @BeforeClass +// public static void setUp () throws NoSuchFieldException, SecurityException, Exception, IllegalAccessException { +// AAFcli cli = JU_AAFCli.getAAfCli(); +// NS ns = new NS(cli); +// List ls = new List(ns); +// lsAdminRes = new ListAdminResponsible(ls); +// } +// +// @Test +// public void exec() { +// try { +// //TODO: Gabe [JUnit] Not visible for junit +// assertEquals(lsAdminRes._exec(0, "add","del","reset","extend"),500); +// } catch (CadiException e) { +// // TODO Auto-generated catch block +// e.printStackTrace(); +// } catch (APIException e) { +// // TODO Auto-generated catch block +// e.printStackTrace(); +// } catch (LocatorException e) { +// // TODO Auto-generated catch block +// e.printStackTrace(); +// } +// } + + @Test //TODO: Temporary fix AAF-111 + public void netYetTested() { + fail("Tests not yet implemented"); + } +} + diff --git a/auth/auth-cmd/src/test/java/org/onap/aaf/auth/cmd/test/ns/JU_ListByName.java b/auth/auth-cmd/src/test/java/org/onap/aaf/auth/cmd/test/ns/JU_ListByName.java new file mode 100644 index 00000000..69e081ab --- /dev/null +++ b/auth/auth-cmd/src/test/java/org/onap/aaf/auth/cmd/test/ns/JU_ListByName.java @@ -0,0 +1,74 @@ +/******************************************************************************* + * ============LICENSE_START==================================================== + * * org.onap.aaf + * * =========================================================================== + * * Copyright © 2017 AT&T Intellectual Property. All rights reserved. + * * =========================================================================== + * * 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==================================================== + * * + * * + ******************************************************************************/ +package org.onap.aaf.auth.cmd.test.ns; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; + +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.runners.MockitoJUnitRunner; +import org.onap.aaf.auth.cmd.AAFcli; +import org.onap.aaf.auth.cmd.ns.List; +import org.onap.aaf.auth.cmd.ns.ListByName; +import org.onap.aaf.auth.cmd.ns.NS; +import org.onap.aaf.auth.cmd.test.JU_AAFCli; +import org.onap.aaf.cadi.CadiException; +import org.onap.aaf.cadi.LocatorException; +import org.onap.aaf.misc.env.APIException; + +@RunWith(MockitoJUnitRunner.class) +public class JU_ListByName { + +// private static ListByName lsByName; +// +// @BeforeClass +// public static void setUp () throws NoSuchFieldException, SecurityException, Exception, IllegalAccessException { +// AAFcli cli = JU_AAFCli.getAAfCli(); +// NS ns = new NS(cli); +// List ls = new List(ns); +// lsByName = new ListByName(ls); +// } +// +// @Test +// public void exec() { +// try { +// assertEquals(lsByName._exec(0, "add","del","reset","extend"),500); +// } catch (CadiException e) { +// // TODO Auto-generated catch block +// e.printStackTrace(); +// } catch (APIException e) { +// // TODO Auto-generated catch block +// e.printStackTrace(); +// } catch (LocatorException e) { +// // TODO Auto-generated catch block +// e.printStackTrace(); +// } +// } + + @Test //TODO: Temporary fix AAF-111 + public void netYetTested() { + fail("Tests not yet implemented"); + } +} + diff --git a/auth/auth-cmd/src/test/java/org/onap/aaf/auth/cmd/test/ns/JU_ListChildren.java b/auth/auth-cmd/src/test/java/org/onap/aaf/auth/cmd/test/ns/JU_ListChildren.java new file mode 100644 index 00000000..c13a52f8 --- /dev/null +++ b/auth/auth-cmd/src/test/java/org/onap/aaf/auth/cmd/test/ns/JU_ListChildren.java @@ -0,0 +1,74 @@ +/******************************************************************************* + * ============LICENSE_START==================================================== + * * org.onap.aaf + * * =========================================================================== + * * Copyright © 2017 AT&T Intellectual Property. All rights reserved. + * * =========================================================================== + * * 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==================================================== + * * + * * + ******************************************************************************/ +package org.onap.aaf.auth.cmd.test.ns; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; + +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.runners.MockitoJUnitRunner; +import org.onap.aaf.auth.cmd.AAFcli; +import org.onap.aaf.auth.cmd.ns.List; +import org.onap.aaf.auth.cmd.ns.ListChildren; +import org.onap.aaf.auth.cmd.ns.NS; +import org.onap.aaf.auth.cmd.test.JU_AAFCli; +import org.onap.aaf.cadi.CadiException; +import org.onap.aaf.cadi.LocatorException; +import org.onap.aaf.misc.env.APIException; + +@RunWith(MockitoJUnitRunner.class) +public class JU_ListChildren { +// +// private static ListChildren lsChildren; +// +// @BeforeClass +// public static void setUp () throws NoSuchFieldException, SecurityException, Exception, IllegalAccessException { +// AAFcli cli = JU_AAFCli.getAAfCli(); +// NS ns = new NS(cli); +// List ls = new List(ns); +// lsChildren = new ListChildren(ls); +// } +// +// @Test +// public void exec() { +// try { +// assertEquals(lsChildren._exec(0, "add","del","reset","extend"),500); +// } catch (CadiException e) { +// // TODO Auto-generated catch block +// e.printStackTrace(); +// } catch (APIException e) { +// // TODO Auto-generated catch block +// e.printStackTrace(); +// } catch (LocatorException e) { +// // TODO Auto-generated catch block +// e.printStackTrace(); +// } +// } + + @Test //TODO: Temporary fix AAF-111 + public void netYetTested() { + fail("Tests not yet implemented"); + } +} + diff --git a/auth/auth-cmd/src/test/java/org/onap/aaf/auth/cmd/test/ns/JU_ListNsKeysByAttrib.java b/auth/auth-cmd/src/test/java/org/onap/aaf/auth/cmd/test/ns/JU_ListNsKeysByAttrib.java new file mode 100644 index 00000000..ac00c256 --- /dev/null +++ b/auth/auth-cmd/src/test/java/org/onap/aaf/auth/cmd/test/ns/JU_ListNsKeysByAttrib.java @@ -0,0 +1,74 @@ +/******************************************************************************* + * ============LICENSE_START==================================================== + * * org.onap.aaf + * * =========================================================================== + * * Copyright © 2017 AT&T Intellectual Property. All rights reserved. + * * =========================================================================== + * * 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==================================================== + * * + * * + ******************************************************************************/ +package org.onap.aaf.auth.cmd.test.ns; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; + +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.runners.MockitoJUnitRunner; +import org.onap.aaf.auth.cmd.AAFcli; +import org.onap.aaf.auth.cmd.ns.List; +import org.onap.aaf.auth.cmd.ns.ListNsKeysByAttrib; +import org.onap.aaf.auth.cmd.ns.NS; +import org.onap.aaf.auth.cmd.test.JU_AAFCli; +import org.onap.aaf.cadi.CadiException; +import org.onap.aaf.cadi.LocatorException; +import org.onap.aaf.misc.env.APIException; + +@RunWith(MockitoJUnitRunner.class) +public class JU_ListNsKeysByAttrib { + +// private static ListNsKeysByAttrib lsNsKeys; +// +// @BeforeClass +// public static void setUp () throws NoSuchFieldException, SecurityException, Exception, IllegalAccessException { +// AAFcli cli = JU_AAFCli.getAAfCli(); +// NS ns = new NS(cli); +// List ls = new List(ns); +// lsNsKeys = new ListNsKeysByAttrib(ls); +// } +// +// @Test +// public void exec() { +// try { +// assertEquals(lsNsKeys._exec(0, "add","del","reset","extend"),500); +// } catch (CadiException e) { +// // TODO Auto-generated catch block +// e.printStackTrace(); +// } catch (APIException e) { +// // TODO Auto-generated catch block +// e.printStackTrace(); +// } catch (LocatorException e) { +// // TODO Auto-generated catch block +// e.printStackTrace(); +// } +// } + + @Test //TODO: Temporary fix AAF-111 + public void netYetTested() { + fail("Tests not yet implemented"); + } +} + diff --git a/auth/auth-cmd/src/test/java/org/onap/aaf/auth/cmd/test/ns/JU_ListUsersInRole.java b/auth/auth-cmd/src/test/java/org/onap/aaf/auth/cmd/test/ns/JU_ListUsersInRole.java new file mode 100644 index 00000000..704f6e4d --- /dev/null +++ b/auth/auth-cmd/src/test/java/org/onap/aaf/auth/cmd/test/ns/JU_ListUsersInRole.java @@ -0,0 +1,76 @@ +/******************************************************************************* + * ============LICENSE_START==================================================== + * * org.onap.aaf + * * =========================================================================== + * * Copyright © 2017 AT&T Intellectual Property. All rights reserved. + * * =========================================================================== + * * 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==================================================== + * * + * * + ******************************************************************************/ +package org.onap.aaf.auth.cmd.test.ns; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; + +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.runners.MockitoJUnitRunner; +import org.onap.aaf.auth.cmd.AAFcli; +import org.onap.aaf.auth.cmd.ns.List; +import org.onap.aaf.auth.cmd.ns.ListUsers; +import org.onap.aaf.auth.cmd.ns.ListUsersInRole; +import org.onap.aaf.auth.cmd.ns.NS; +import org.onap.aaf.auth.cmd.test.JU_AAFCli; + +@RunWith(MockitoJUnitRunner.class) +public class JU_ListUsersInRole { + +// private static ListUsersInRole lsUserinRole; +// +// @BeforeClass +// public static void setUp() throws NoSuchFieldException, SecurityException, Exception, IllegalAccessException { +// AAFcli cli = JU_AAFCli.getAAfCli(); +// NS ns = new NS(cli); +// List ls = new List(ns);//possible wrong import, remove import org.onap.aaf.auth.cmd.ns to see other options +// ListUsers lsU = new ListUsers(ls); +// lsUserinRole = new ListUsersInRole(lsU); +// } +// +// @Test +// public void exec() { +// try { +// assertEquals(lsUserinRole._exec(0, "add", "del", "reset", "extend"), 500); +// } catch (Exception e) { +// assertEquals(e.getMessage(), "java.net.UnknownHostException: DME2RESOLVE"); +// } +// } +// +// @Test +// public void detailedHelp() { +// boolean hasNoError = true; +// try { +// lsUserinRole.detailedHelp(1, new StringBuilder("test")); +// } catch (Exception e) { +// hasNoError = false; +// } +// assertEquals(hasNoError, true); +// } + + @Test //TODO: Temporary fix AAF-111 + public void netYetTested() { + fail("Tests not yet implemented"); + } +} diff --git a/auth/auth-cmd/src/test/java/org/onap/aaf/auth/cmd/test/ns/JU_ListUsersWithPerm.java b/auth/auth-cmd/src/test/java/org/onap/aaf/auth/cmd/test/ns/JU_ListUsersWithPerm.java new file mode 100644 index 00000000..06e9cf01 --- /dev/null +++ b/auth/auth-cmd/src/test/java/org/onap/aaf/auth/cmd/test/ns/JU_ListUsersWithPerm.java @@ -0,0 +1,76 @@ +/******************************************************************************* + * ============LICENSE_START==================================================== + * * org.onap.aaf + * * =========================================================================== + * * Copyright © 2017 AT&T Intellectual Property. All rights reserved. + * * =========================================================================== + * * 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==================================================== + * * + * * + ******************************************************************************/ +package org.onap.aaf.auth.cmd.test.ns; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; + +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.runners.MockitoJUnitRunner; +import org.onap.aaf.auth.cmd.AAFcli; +import org.onap.aaf.auth.cmd.ns.List; +import org.onap.aaf.auth.cmd.ns.ListUsers; +import org.onap.aaf.auth.cmd.ns.ListUsersWithPerm; +import org.onap.aaf.auth.cmd.ns.NS; +import org.onap.aaf.auth.cmd.test.JU_AAFCli; + +@RunWith(MockitoJUnitRunner.class) +public class JU_ListUsersWithPerm { + +// private static ListUsersWithPerm lsUserWithPerm; +// +// @BeforeClass +// public static void setUp() throws NoSuchFieldException, SecurityException, Exception, IllegalAccessException { +// AAFcli cli = JU_AAFCli.getAAfCli(); +// NS ns = new NS(cli); +// List ls = new List(ns);//possible wrong import, remove import org.onap.aaf.auth.cmd.ns to see other option +// ListUsers lsU = new ListUsers(ls); +// lsUserWithPerm = new ListUsersWithPerm(lsU); +// } +// +// @Test +// public void exec() { +// try { +// assertEquals(lsUserWithPerm._exec(0, "add", "del", "reset", "extend"), 500); +// } catch (Exception e) { +// assertEquals(e.getMessage(), "java.net.UnknownHostException: DME2RESOLVE"); +// } +// } +// +// @Test +// public void detailedHelp() { +// boolean hasNoError = true; +// try { +// lsUserWithPerm.detailedHelp(1, new StringBuilder("test")); +// } catch (Exception e) { +// hasNoError = false; +// } +// assertEquals(hasNoError, true); +// } + + @Test //TODO: Temporary fix AAF-111 + public void netYetTested() { + fail("Tests not yet implemented"); + } +} diff --git a/auth/auth-cmd/src/test/java/org/onap/aaf/auth/cmd/test/ns/JU_Responsible.java b/auth/auth-cmd/src/test/java/org/onap/aaf/auth/cmd/test/ns/JU_Responsible.java new file mode 100644 index 00000000..ccb4b025 --- /dev/null +++ b/auth/auth-cmd/src/test/java/org/onap/aaf/auth/cmd/test/ns/JU_Responsible.java @@ -0,0 +1,74 @@ +/******************************************************************************* + * ============LICENSE_START==================================================== + * * org.onap.aaf + * * =========================================================================== + * * Copyright © 2017 AT&T Intellectual Property. All rights reserved. + * * =========================================================================== + * * 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==================================================== + * * + * * + ******************************************************************************/ +package org.onap.aaf.auth.cmd.test.ns; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; + +import java.io.IOException; +import java.security.GeneralSecurityException; + +import org.junit.BeforeClass; +import org.junit.Test; +import org.onap.aaf.auth.cmd.AAFcli; +import org.onap.aaf.auth.cmd.test.JU_AAFCli; +import org.onap.aaf.cadi.LocatorException; +import org.onap.aaf.misc.env.APIException; + +public class JU_Responsible { + +// private static Responsible responsible;//TODO: Gabe[JUnit] check with Jonathan +// +// @BeforeClass +// public static void setUp() throws APIException, LocatorException, GeneralSecurityException, IOException { +// AAFcli cli = JU_AAFCli.getAAfCli(); +// NS ns = new NS(cli); +// responsible = new Responsible(ns); +// +// } +// +// @Test +// public void exec1() { +// try { +// responsible._exec(0, "del", "del", "del"); +// } catch (Exception e) { +// assertEquals(e.getMessage(), "java.net.UnknownHostException: DME2RESOLVE"); +// } +// } +// +// @Test +// public void detailedHelp() { +// boolean hasNoError = true; +// try { +// responsible.detailedHelp(1, new StringBuilder("test")); +// } catch (Exception e) { +// hasNoError = false; +// } +// assertEquals(hasNoError, true); +// } + + @Test + public void netYetTested() { + fail("Tests not yet implemented"); + } + +} diff --git a/auth/auth-cmd/src/test/java/org/onap/aaf/auth/cmd/test/perm/JU_Create.java b/auth/auth-cmd/src/test/java/org/onap/aaf/auth/cmd/test/perm/JU_Create.java new file mode 100644 index 00000000..4ae99bed --- /dev/null +++ b/auth/auth-cmd/src/test/java/org/onap/aaf/auth/cmd/test/perm/JU_Create.java @@ -0,0 +1,73 @@ +/******************************************************************************* + * ============LICENSE_START==================================================== + * * org.onap.aaf + * * =========================================================================== + * * Copyright © 2017 AT&T Intellectual Property. All rights reserved. + * * =========================================================================== + * * 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==================================================== + * * + * * + ******************************************************************************/ +package org.onap.aaf.auth.cmd.test.perm; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; + +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.runners.MockitoJUnitRunner; +import org.onap.aaf.auth.cmd.AAFcli; +import org.onap.aaf.auth.cmd.perm.Create; +import org.onap.aaf.auth.cmd.perm.Perm; +import org.onap.aaf.auth.cmd.role.Role; +import org.onap.aaf.auth.cmd.test.JU_AAFCli; +import org.onap.aaf.cadi.CadiException; +import org.onap.aaf.cadi.LocatorException; +import org.onap.aaf.misc.env.APIException; + +@RunWith(MockitoJUnitRunner.class) +public class JU_Create { + +// private static Create create; +// +// @BeforeClass +// public static void setUp () throws NoSuchFieldException, SecurityException, Exception, IllegalAccessException { +// AAFcli cli = JU_AAFCli.getAAfCli(); +// Role role = new Role(cli); +// Perm perm = new Perm(role); +// create = new Create(perm); +// } +// +// @Test +// public void exec() { +// try { +// assertEquals(create._exec(0, "add","del","reset","extend"),500); +// } catch (CadiException e) { +// // TODO Auto-generated catch block +// e.printStackTrace(); +// } catch (APIException e) { +// // TODO Auto-generated catch block +// e.printStackTrace(); +// } catch (LocatorException e) { +// // TODO Auto-generated catch block +// e.printStackTrace(); +// } +// } + + @Test //TODO: Temporary fix AAF-111 + public void netYetTested() { + fail("Tests not yet implemented"); + } +} diff --git a/auth/auth-cmd/src/test/java/org/onap/aaf/auth/cmd/test/perm/JU_Delete.java b/auth/auth-cmd/src/test/java/org/onap/aaf/auth/cmd/test/perm/JU_Delete.java new file mode 100644 index 00000000..ed59013c --- /dev/null +++ b/auth/auth-cmd/src/test/java/org/onap/aaf/auth/cmd/test/perm/JU_Delete.java @@ -0,0 +1,73 @@ +/******************************************************************************* + * ============LICENSE_START==================================================== + * * org.onap.aaf + * * =========================================================================== + * * Copyright © 2017 AT&T Intellectual Property. All rights reserved. + * * =========================================================================== + * * 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==================================================== + * * + * * + ******************************************************************************/ +package org.onap.aaf.auth.cmd.test.perm; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; + +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.runners.MockitoJUnitRunner; +import org.onap.aaf.auth.cmd.AAFcli; +import org.onap.aaf.auth.cmd.perm.Delete; +import org.onap.aaf.auth.cmd.perm.Perm; +import org.onap.aaf.auth.cmd.role.Role; +import org.onap.aaf.auth.cmd.test.JU_AAFCli; +import org.onap.aaf.cadi.CadiException; +import org.onap.aaf.cadi.LocatorException; +import org.onap.aaf.misc.env.APIException; + +@RunWith(MockitoJUnitRunner.class) +public class JU_Delete { + +// private static Delete del; +// +// @BeforeClass +// public static void setUp () throws NoSuchFieldException, SecurityException, Exception, IllegalAccessException { +// AAFcli cli = JU_AAFCli.getAAfCli(); +// Role role = new Role(cli); +// Perm perm = new Perm(role); +// del = new Delete(perm); +// } +// +// @Test +// public void exec() { +// try { +// assertEquals(del._exec(0, "add","del","reset","extend"),500); +// } catch (CadiException e) { +// // TODO Auto-generated catch block +// e.printStackTrace(); +// } catch (APIException e) { +// // TODO Auto-generated catch block +// e.printStackTrace(); +// } catch (LocatorException e) { +// // TODO Auto-generated catch block +// e.printStackTrace(); +// } +// } + + @Test //TODO: Temporary fix AAF-111 + public void netYetTested() { + fail("Tests not yet implemented"); + } +} diff --git a/auth/auth-cmd/src/test/java/org/onap/aaf/auth/cmd/test/perm/JU_Describe.java b/auth/auth-cmd/src/test/java/org/onap/aaf/auth/cmd/test/perm/JU_Describe.java new file mode 100644 index 00000000..8861e6f1 --- /dev/null +++ b/auth/auth-cmd/src/test/java/org/onap/aaf/auth/cmd/test/perm/JU_Describe.java @@ -0,0 +1,73 @@ +/******************************************************************************* + * ============LICENSE_START==================================================== + * * org.onap.aaf + * * =========================================================================== + * * Copyright © 2017 AT&T Intellectual Property. All rights reserved. + * * =========================================================================== + * * 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==================================================== + * * + * * + ******************************************************************************/ +package org.onap.aaf.auth.cmd.test.perm; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; + +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.runners.MockitoJUnitRunner; +import org.onap.aaf.auth.cmd.AAFcli; +import org.onap.aaf.auth.cmd.perm.Describe; +import org.onap.aaf.auth.cmd.perm.Perm; +import org.onap.aaf.auth.cmd.role.Role; +import org.onap.aaf.auth.cmd.test.JU_AAFCli; +import org.onap.aaf.cadi.CadiException; +import org.onap.aaf.cadi.LocatorException; +import org.onap.aaf.misc.env.APIException; + +@RunWith(MockitoJUnitRunner.class) +public class JU_Describe { +// +// private static Describe desc; +// +// @BeforeClass +// public static void setUp () throws NoSuchFieldException, SecurityException, Exception, IllegalAccessException { +// AAFcli cli = JU_AAFCli.getAAfCli(); +// Role role = new Role(cli); +// Perm perm = new Perm(role); +// desc = new Describe(perm); +// } +// +// @Test +// public void exec() { +// try { +// assertEquals(desc._exec(0, "add","del","reset","extend"),500); +// } catch (CadiException e) { +// // TODO Auto-generated catch block +// e.printStackTrace(); +// } catch (APIException e) { +// // TODO Auto-generated catch block +// e.printStackTrace(); +// } catch (LocatorException e) { +// // TODO Auto-generated catch block +// e.printStackTrace(); +// } +// } + + @Test //TODO: Temporary fix AAF-111 + public void netYetTested() { + fail("Tests not yet implemented"); + } +} diff --git a/auth/auth-cmd/src/test/java/org/onap/aaf/auth/cmd/test/perm/JU_Grant.java b/auth/auth-cmd/src/test/java/org/onap/aaf/auth/cmd/test/perm/JU_Grant.java new file mode 100644 index 00000000..9bfa3f4a --- /dev/null +++ b/auth/auth-cmd/src/test/java/org/onap/aaf/auth/cmd/test/perm/JU_Grant.java @@ -0,0 +1,73 @@ +/******************************************************************************* + * ============LICENSE_START==================================================== + * * org.onap.aaf + * * =========================================================================== + * * Copyright © 2017 AT&T Intellectual Property. All rights reserved. + * * =========================================================================== + * * 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==================================================== + * * + * * + ******************************************************************************/ +package org.onap.aaf.auth.cmd.test.perm; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; + +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.runners.MockitoJUnitRunner; +import org.onap.aaf.auth.cmd.AAFcli; +import org.onap.aaf.auth.cmd.perm.Grant; +import org.onap.aaf.auth.cmd.perm.Perm; +import org.onap.aaf.auth.cmd.role.Role; +import org.onap.aaf.auth.cmd.test.JU_AAFCli; +import org.onap.aaf.cadi.CadiException; +import org.onap.aaf.cadi.LocatorException; +import org.onap.aaf.misc.env.APIException; + +@RunWith(MockitoJUnitRunner.class) +public class JU_Grant { + +// private static Grant grant; +// +// @BeforeClass +// public static void setUp () throws NoSuchFieldException, SecurityException, Exception, IllegalAccessException { +// AAFcli cli = JU_AAFCli.getAAfCli(); +// Role role = new Role(cli); +// Perm perm = new Perm(role); +// grant = new Grant(perm); +// } +// +// @Test +// public void exec() { +// try { +// assertEquals(grant._exec(0, "add","del","reset","extend"),500); +// } catch (CadiException e) { +// // TODO Auto-generated catch block +// e.printStackTrace(); +// } catch (APIException e) { +// // TODO Auto-generated catch block +// e.printStackTrace(); +// } catch (LocatorException e) { +// // TODO Auto-generated catch block +// e.printStackTrace(); +// } +// } + + @Test //TODO: Temporary fix AAF-111 + public void netYetTested() { + fail("Tests not yet implemented"); + } +} diff --git a/auth/auth-cmd/src/test/java/org/onap/aaf/auth/cmd/test/perm/JU_ListActivity.java b/auth/auth-cmd/src/test/java/org/onap/aaf/auth/cmd/test/perm/JU_ListActivity.java new file mode 100644 index 00000000..fd4e08b7 --- /dev/null +++ b/auth/auth-cmd/src/test/java/org/onap/aaf/auth/cmd/test/perm/JU_ListActivity.java @@ -0,0 +1,75 @@ +/******************************************************************************* + * ============LICENSE_START==================================================== + * * org.onap.aaf + * * =========================================================================== + * * Copyright © 2017 AT&T Intellectual Property. All rights reserved. + * * =========================================================================== + * * 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==================================================== + * * + * * + ******************************************************************************/ +package org.onap.aaf.auth.cmd.test.perm; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; + +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.runners.MockitoJUnitRunner; +import org.onap.aaf.auth.cmd.AAFcli; +import org.onap.aaf.auth.cmd.perm.List; +import org.onap.aaf.auth.cmd.perm.ListActivity; +import org.onap.aaf.auth.cmd.perm.Perm; +import org.onap.aaf.auth.cmd.role.Role; +import org.onap.aaf.auth.cmd.test.JU_AAFCli; +import org.onap.aaf.cadi.CadiException; +import org.onap.aaf.cadi.LocatorException; +import org.onap.aaf.misc.env.APIException; + +@RunWith(MockitoJUnitRunner.class) +public class JU_ListActivity { + +// private static ListActivity lsActivity; +// +// @BeforeClass +// public static void setUp () throws NoSuchFieldException, SecurityException, Exception, IllegalAccessException { +// AAFcli cli = JU_AAFCli.getAAfCli(); +// Role role = new Role(cli); +// Perm perm = new Perm(role); +// List ls = new List(perm); +// lsActivity = new ListActivity(ls); +// } +// +// @Test +// public void exec() { +// try { +// assertEquals(lsActivity._exec(0, "add","del","reset","extend"),500); +// } catch (CadiException e) { +// // TODO Auto-generated catch block +// e.printStackTrace(); +// } catch (APIException e) { +// // TODO Auto-generated catch block +// e.printStackTrace(); +// } catch (LocatorException e) { +// // TODO Auto-generated catch block +// e.printStackTrace(); +// } +// } + + @Test //TODO: Temporary fix AAF-111 + public void netYetTested() { + fail("Tests not yet implemented"); + } +} diff --git a/auth/auth-cmd/src/test/java/org/onap/aaf/auth/cmd/test/perm/JU_ListByNS.java b/auth/auth-cmd/src/test/java/org/onap/aaf/auth/cmd/test/perm/JU_ListByNS.java new file mode 100644 index 00000000..fc4b6913 --- /dev/null +++ b/auth/auth-cmd/src/test/java/org/onap/aaf/auth/cmd/test/perm/JU_ListByNS.java @@ -0,0 +1,75 @@ +/******************************************************************************* + * ============LICENSE_START==================================================== + * * org.onap.aaf + * * =========================================================================== + * * Copyright © 2017 AT&T Intellectual Property. All rights reserved. + * * =========================================================================== + * * 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==================================================== + * * + * * + ******************************************************************************/ +package org.onap.aaf.auth.cmd.test.perm; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; + +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.runners.MockitoJUnitRunner; +import org.onap.aaf.auth.cmd.AAFcli; +import org.onap.aaf.auth.cmd.perm.List; +import org.onap.aaf.auth.cmd.perm.ListByNS; +import org.onap.aaf.auth.cmd.perm.Perm; +import org.onap.aaf.auth.cmd.role.Role; +import org.onap.aaf.auth.cmd.test.JU_AAFCli; +import org.onap.aaf.cadi.CadiException; +import org.onap.aaf.cadi.LocatorException; +import org.onap.aaf.misc.env.APIException; + +@RunWith(MockitoJUnitRunner.class) +public class JU_ListByNS { + +// private static ListByNS lsByNS; +// +// @BeforeClass +// public static void setUp () throws NoSuchFieldException, SecurityException, Exception, IllegalAccessException { +// AAFcli cli = JU_AAFCli.getAAfCli(); +// Role role = new Role(cli); +// Perm perm = new Perm(role); +// List ls = new List(perm); +// lsByNS = new ListByNS(ls); +// } +// +// @Test +// public void exec() { +// try { +// assertEquals(lsByNS._exec(0, "add","del","reset","extend"),500); +// } catch (CadiException e) { +// // TODO Auto-generated catch block +// e.printStackTrace(); +// } catch (APIException e) { +// // TODO Auto-generated catch block +// e.printStackTrace(); +// } catch (LocatorException e) { +// // TODO Auto-generated catch block +// e.printStackTrace(); +// } +// } + + @Test //TODO: Temporary fix AAF-111 + public void netYetTested() { + fail("Tests not yet implemented"); + } +} diff --git a/auth/auth-cmd/src/test/java/org/onap/aaf/auth/cmd/test/perm/JU_ListByName.java b/auth/auth-cmd/src/test/java/org/onap/aaf/auth/cmd/test/perm/JU_ListByName.java new file mode 100644 index 00000000..7e65dfc0 --- /dev/null +++ b/auth/auth-cmd/src/test/java/org/onap/aaf/auth/cmd/test/perm/JU_ListByName.java @@ -0,0 +1,75 @@ +/******************************************************************************* + * ============LICENSE_START==================================================== + * * org.onap.aaf + * * =========================================================================== + * * Copyright © 2017 AT&T Intellectual Property. All rights reserved. + * * =========================================================================== + * * 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==================================================== + * * + * * + ******************************************************************************/ +package org.onap.aaf.auth.cmd.test.perm; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; + +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.runners.MockitoJUnitRunner; +import org.onap.aaf.auth.cmd.AAFcli; +import org.onap.aaf.auth.cmd.perm.List; +import org.onap.aaf.auth.cmd.perm.ListByName; +import org.onap.aaf.auth.cmd.perm.Perm; +import org.onap.aaf.auth.cmd.role.Role; +import org.onap.aaf.auth.cmd.test.JU_AAFCli; +import org.onap.aaf.cadi.CadiException; +import org.onap.aaf.cadi.LocatorException; +import org.onap.aaf.misc.env.APIException; + +@RunWith(MockitoJUnitRunner.class) +public class JU_ListByName { + +// private static ListByName lsByName; +// +// @BeforeClass +// public static void setUp () throws NoSuchFieldException, SecurityException, Exception, IllegalAccessException { +// AAFcli cli = JU_AAFCli.getAAfCli(); +// Role role = new Role(cli); +// Perm perm = new Perm(role); +// List ls = new List(perm); +// lsByName = new ListByName(ls); +// } +// +// @Test +// public void exec() { +// try { +// assertEquals(lsByName._exec(0, "add","del","reset","extend"),500); +// } catch (CadiException e) { +// // TODO Auto-generated catch block +// e.printStackTrace(); +// } catch (APIException e) { +// // TODO Auto-generated catch block +// e.printStackTrace(); +// } catch (LocatorException e) { +// // TODO Auto-generated catch block +// e.printStackTrace(); +// } +// } + + @Test //TODO: Temporary fix AAF-111 + public void netYetTested() { + fail("Tests not yet implemented"); + } +} diff --git a/auth/auth-cmd/src/test/java/org/onap/aaf/auth/cmd/test/perm/JU_ListByRole.java b/auth/auth-cmd/src/test/java/org/onap/aaf/auth/cmd/test/perm/JU_ListByRole.java new file mode 100644 index 00000000..d2d89783 --- /dev/null +++ b/auth/auth-cmd/src/test/java/org/onap/aaf/auth/cmd/test/perm/JU_ListByRole.java @@ -0,0 +1,75 @@ +/******************************************************************************* + * ============LICENSE_START==================================================== + * * org.onap.aaf + * * =========================================================================== + * * Copyright © 2017 AT&T Intellectual Property. All rights reserved. + * * =========================================================================== + * * 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==================================================== + * * + * * + ******************************************************************************/ +package org.onap.aaf.auth.cmd.test.perm; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; + +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.runners.MockitoJUnitRunner; +import org.onap.aaf.auth.cmd.AAFcli; +import org.onap.aaf.auth.cmd.perm.List; +import org.onap.aaf.auth.cmd.perm.ListByRole; +import org.onap.aaf.auth.cmd.perm.Perm; +import org.onap.aaf.auth.cmd.role.Role; +import org.onap.aaf.auth.cmd.test.JU_AAFCli; +import org.onap.aaf.cadi.CadiException; +import org.onap.aaf.cadi.LocatorException; +import org.onap.aaf.misc.env.APIException; + +@RunWith(MockitoJUnitRunner.class) +public class JU_ListByRole { + +// private static ListByRole lsByRole; +// +// @BeforeClass +// public static void setUp () throws NoSuchFieldException, SecurityException, Exception, IllegalAccessException { +// AAFcli cli = JU_AAFCli.getAAfCli(); +// Role role = new Role(cli); +// Perm perm = new Perm(role); +// List ls = new List(perm); +// lsByRole = new ListByRole(ls); +// } +// +// @Test +// public void exec() { +// try { +// assertEquals(lsByRole._exec(0, "add","del","reset","extend"),500); +// } catch (CadiException e) { +// // TODO Auto-generated catch block +// e.printStackTrace(); +// } catch (APIException e) { +// // TODO Auto-generated catch block +// e.printStackTrace(); +// } catch (LocatorException e) { +// // TODO Auto-generated catch block +// e.printStackTrace(); +// } +// } + + @Test //TODO: Temporary fix AAF-111 + public void netYetTested() { + fail("Tests not yet implemented"); + } +} diff --git a/auth/auth-cmd/src/test/java/org/onap/aaf/auth/cmd/test/perm/JU_ListByUser.java b/auth/auth-cmd/src/test/java/org/onap/aaf/auth/cmd/test/perm/JU_ListByUser.java new file mode 100644 index 00000000..675a02aa --- /dev/null +++ b/auth/auth-cmd/src/test/java/org/onap/aaf/auth/cmd/test/perm/JU_ListByUser.java @@ -0,0 +1,75 @@ +/******************************************************************************* + * ============LICENSE_START==================================================== + * * org.onap.aaf + * * =========================================================================== + * * Copyright © 2017 AT&T Intellectual Property. All rights reserved. + * * =========================================================================== + * * 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==================================================== + * * + * * + ******************************************************************************/ +package org.onap.aaf.auth.cmd.test.perm; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; + +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.runners.MockitoJUnitRunner; +import org.onap.aaf.auth.cmd.AAFcli; +import org.onap.aaf.auth.cmd.perm.List; +import org.onap.aaf.auth.cmd.perm.ListByUser; +import org.onap.aaf.auth.cmd.perm.Perm; +import org.onap.aaf.auth.cmd.role.Role; +import org.onap.aaf.auth.cmd.test.JU_AAFCli; +import org.onap.aaf.cadi.CadiException; +import org.onap.aaf.cadi.LocatorException; +import org.onap.aaf.misc.env.APIException; + +@RunWith(MockitoJUnitRunner.class) +public class JU_ListByUser { + +// private static ListByUser lsByName; +// +// @BeforeClass +// public static void setUp () throws NoSuchFieldException, SecurityException, Exception, IllegalAccessException { +// AAFcli cli = JU_AAFCli.getAAfCli(); +// Role role = new Role(cli); +// Perm perm = new Perm(role); +// List ls = new List(perm); +// lsByName = new ListByUser(ls); +// } +// +// @Test +// public void exec() { +// try { +// assertEquals(lsByName._exec(0, "add","del","reset","extend"),500); +// } catch (CadiException e) { +// // TODO Auto-generated catch block +// e.printStackTrace(); +// } catch (APIException e) { +// // TODO Auto-generated catch block +// e.printStackTrace(); +// } catch (LocatorException e) { +// // TODO Auto-generated catch block +// e.printStackTrace(); +// } +// } + + @Test //TODO: Temporary fix AAF-111 + public void netYetTested() { + fail("Tests not yet implemented"); + } +} diff --git a/auth/auth-cmd/src/test/java/org/onap/aaf/auth/cmd/test/perm/JU_Rename.java b/auth/auth-cmd/src/test/java/org/onap/aaf/auth/cmd/test/perm/JU_Rename.java new file mode 100644 index 00000000..39263f1b --- /dev/null +++ b/auth/auth-cmd/src/test/java/org/onap/aaf/auth/cmd/test/perm/JU_Rename.java @@ -0,0 +1,73 @@ +/******************************************************************************* + * ============LICENSE_START==================================================== + * * org.onap.aaf + * * =========================================================================== + * * Copyright © 2017 AT&T Intellectual Property. All rights reserved. + * * =========================================================================== + * * 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==================================================== + * * + * * + ******************************************************************************/ +package org.onap.aaf.auth.cmd.test.perm; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; + +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.runners.MockitoJUnitRunner; +import org.onap.aaf.auth.cmd.AAFcli; +import org.onap.aaf.auth.cmd.perm.Perm; +import org.onap.aaf.auth.cmd.perm.Rename; +import org.onap.aaf.auth.cmd.role.Role; +import org.onap.aaf.auth.cmd.test.JU_AAFCli; +import org.onap.aaf.cadi.CadiException; +import org.onap.aaf.cadi.LocatorException; +import org.onap.aaf.misc.env.APIException; + +@RunWith(MockitoJUnitRunner.class) +public class JU_Rename { + +// private static Rename rename; +// +// @BeforeClass +// public static void setUp () throws NoSuchFieldException, SecurityException, Exception, IllegalAccessException { +// AAFcli cli = JU_AAFCli.getAAfCli(); +// Role role = new Role(cli); +// Perm perm = new Perm(role); +// rename = new Rename(perm); +// } +// +// @Test +// public void exec() { +// try { +// assertEquals(rename._exec(0, "add","del","reset","extend","clear", "rename", "create"),500); +// } catch (CadiException e) { +// // TODO Auto-generated catch block +// e.printStackTrace(); +// } catch (APIException e) { +// // TODO Auto-generated catch block +// e.printStackTrace(); +// } catch (LocatorException e) { +// // TODO Auto-generated catch block +// e.printStackTrace(); +// } +// } + + @Test //TODO: Temporary fix AAF-111 + public void netYetTested() { + fail("Tests not yet implemented"); + } +} diff --git a/auth/auth-cmd/src/test/java/org/onap/aaf/auth/cmd/test/role/JU_CreateDelete.java b/auth/auth-cmd/src/test/java/org/onap/aaf/auth/cmd/test/role/JU_CreateDelete.java new file mode 100644 index 00000000..c19bd5c2 --- /dev/null +++ b/auth/auth-cmd/src/test/java/org/onap/aaf/auth/cmd/test/role/JU_CreateDelete.java @@ -0,0 +1,71 @@ +/******************************************************************************* + * ============LICENSE_START==================================================== + * * org.onap.aaf + * * =========================================================================== + * * Copyright © 2017 AT&T Intellectual Property. All rights reserved. + * * =========================================================================== + * * 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==================================================== + * * + * * + ******************************************************************************/ +package org.onap.aaf.auth.cmd.test.role; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; + +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.runners.MockitoJUnitRunner; +import org.onap.aaf.auth.cmd.AAFcli; +import org.onap.aaf.auth.cmd.role.CreateDelete; +import org.onap.aaf.auth.cmd.role.Role; +import org.onap.aaf.auth.cmd.test.JU_AAFCli; +import org.onap.aaf.cadi.CadiException; +import org.onap.aaf.cadi.LocatorException; +import org.onap.aaf.misc.env.APIException; + +@RunWith(MockitoJUnitRunner.class) +public class JU_CreateDelete { + +// private static CreateDelete createDel; +// +// @BeforeClass +// public static void setUp () throws NoSuchFieldException, SecurityException, Exception, IllegalAccessException { +// AAFcli cli = JU_AAFCli.getAAfCli(); +// Role role = new Role(cli); +// createDel = new CreateDelete(role); +// } +// +// @Test +// public void exec() { +// try { +// assertEquals(createDel._exec(0, "add","del","reset","extend","clear", "rename", "create"),500); +// } catch (CadiException e) { +// // TODO Auto-generated catch block +// e.printStackTrace(); +// } catch (APIException e) { +// // TODO Auto-generated catch block +// e.printStackTrace(); +// } catch (LocatorException e) { +// // TODO Auto-generated catch block +// e.printStackTrace(); +// } +// } + + @Test //TODO: Temporary fix AAF-111 + public void netYetTested() { + fail("Tests not yet implemented"); + } +} diff --git a/auth/auth-cmd/src/test/java/org/onap/aaf/auth/cmd/test/role/JU_Describe.java b/auth/auth-cmd/src/test/java/org/onap/aaf/auth/cmd/test/role/JU_Describe.java new file mode 100644 index 00000000..8dd9558e --- /dev/null +++ b/auth/auth-cmd/src/test/java/org/onap/aaf/auth/cmd/test/role/JU_Describe.java @@ -0,0 +1,71 @@ +/******************************************************************************* + * ============LICENSE_START==================================================== + * * org.onap.aaf + * * =========================================================================== + * * Copyright © 2017 AT&T Intellectual Property. All rights reserved. + * * =========================================================================== + * * 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==================================================== + * * + * * + ******************************************************************************/ +package org.onap.aaf.auth.cmd.test.role; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; + +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.runners.MockitoJUnitRunner; +import org.onap.aaf.auth.cmd.AAFcli; +import org.onap.aaf.auth.cmd.role.Describe; +import org.onap.aaf.auth.cmd.role.Role; +import org.onap.aaf.auth.cmd.test.JU_AAFCli; +import org.onap.aaf.cadi.CadiException; +import org.onap.aaf.cadi.LocatorException; +import org.onap.aaf.misc.env.APIException; + +@RunWith(MockitoJUnitRunner.class) +public class JU_Describe { + +// private static Describe desc; +// +// @BeforeClass +// public static void setUp () throws NoSuchFieldException, SecurityException, Exception, IllegalAccessException { +// AAFcli cli = JU_AAFCli.getAAfCli(); +// Role role = new Role(cli); +// desc = new Describe(role); +// } +// +// @Test +// public void exec() { +// try { +// assertEquals(desc._exec(0, "add","del","reset","extend","clear", "rename", "create"),500); +// } catch (CadiException e) { +// // TODO Auto-generated catch block +// e.printStackTrace(); +// } catch (APIException e) { +// // TODO Auto-generated catch block +// e.printStackTrace(); +// } catch (LocatorException e) { +// // TODO Auto-generated catch block +// e.printStackTrace(); +// } +// } + + @Test //TODO: Temporary fix AAF-111 + public void netYetTested() { + fail("Tests not yet implemented"); + } +} diff --git a/auth/auth-cmd/src/test/java/org/onap/aaf/auth/cmd/test/role/JU_ListActivity.java b/auth/auth-cmd/src/test/java/org/onap/aaf/auth/cmd/test/role/JU_ListActivity.java new file mode 100644 index 00000000..79f8d681 --- /dev/null +++ b/auth/auth-cmd/src/test/java/org/onap/aaf/auth/cmd/test/role/JU_ListActivity.java @@ -0,0 +1,73 @@ +/******************************************************************************* + * ============LICENSE_START==================================================== + * * org.onap.aaf + * * =========================================================================== + * * Copyright © 2017 AT&T Intellectual Property. All rights reserved. + * * =========================================================================== + * * 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==================================================== + * * + * * + ******************************************************************************/ +package org.onap.aaf.auth.cmd.test.role; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; + +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.runners.MockitoJUnitRunner; +import org.onap.aaf.auth.cmd.AAFcli; +import org.onap.aaf.auth.cmd.role.List; +import org.onap.aaf.auth.cmd.role.ListActivity; +import org.onap.aaf.auth.cmd.role.Role; +import org.onap.aaf.auth.cmd.test.JU_AAFCli; +import org.onap.aaf.cadi.CadiException; +import org.onap.aaf.cadi.LocatorException; +import org.onap.aaf.misc.env.APIException; + +@RunWith(MockitoJUnitRunner.class) +public class JU_ListActivity { +// +// private static ListActivity lsActivity; +// +// @BeforeClass +// public static void setUp () throws NoSuchFieldException, SecurityException, Exception, IllegalAccessException { +// AAFcli cli = JU_AAFCli.getAAfCli(); +// Role role = new Role(cli); +// List ls = new List(role); +// lsActivity = new ListActivity(ls); +// } +// +// @Test +// public void exec() { +// try { +// assertEquals(lsActivity._exec(0, "add","del","reset","extend","clear", "rename", "create"),500); +// } catch (CadiException e) { +// // TODO Auto-generated catch block +// e.printStackTrace(); +// } catch (APIException e) { +// // TODO Auto-generated catch block +// e.printStackTrace(); +// } catch (LocatorException e) { +// // TODO Auto-generated catch block +// e.printStackTrace(); +// } +// } + + @Test //TODO: Temporary fix AAF-111 + public void netYetTested() { + fail("Tests not yet implemented"); + } +} diff --git a/auth/auth-cmd/src/test/java/org/onap/aaf/auth/cmd/test/role/JU_ListByNS.java b/auth/auth-cmd/src/test/java/org/onap/aaf/auth/cmd/test/role/JU_ListByNS.java new file mode 100644 index 00000000..5eb188d3 --- /dev/null +++ b/auth/auth-cmd/src/test/java/org/onap/aaf/auth/cmd/test/role/JU_ListByNS.java @@ -0,0 +1,73 @@ +/******************************************************************************* + * ============LICENSE_START==================================================== + * * org.onap.aaf + * * =========================================================================== + * * Copyright © 2017 AT&T Intellectual Property. All rights reserved. + * * =========================================================================== + * * 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==================================================== + * * + * * + ******************************************************************************/ +package org.onap.aaf.auth.cmd.test.role; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; + +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.runners.MockitoJUnitRunner; +import org.onap.aaf.auth.cmd.AAFcli; +import org.onap.aaf.auth.cmd.role.List; +import org.onap.aaf.auth.cmd.role.ListByNS; +import org.onap.aaf.auth.cmd.role.Role; +import org.onap.aaf.auth.cmd.test.JU_AAFCli; +import org.onap.aaf.cadi.CadiException; +import org.onap.aaf.cadi.LocatorException; +import org.onap.aaf.misc.env.APIException; + +@RunWith(MockitoJUnitRunner.class) +public class JU_ListByNS { + +// private static ListByNS lsByNS; +// +// @BeforeClass +// public static void setUp () throws NoSuchFieldException, SecurityException, Exception, IllegalAccessException { +// AAFcli cli = JU_AAFCli.getAAfCli(); +// Role role = new Role(cli); +// List ls = new List(role); +// lsByNS = new ListByNS(ls); +// } +// +// @Test +// public void exec() { +// try { +// assertEquals(lsByNS._exec(0, "add","del","reset","extend","clear", "rename", "create"),500); +// } catch (CadiException e) { +// // TODO Auto-generated catch block +// e.printStackTrace(); +// } catch (APIException e) { +// // TODO Auto-generated catch block +// e.printStackTrace(); +// } catch (LocatorException e) { +// // TODO Auto-generated catch block +// e.printStackTrace(); +// } +// } + + @Test //TODO: Temporary fix AAF-111 + public void netYetTested() { + fail("Tests not yet implemented"); + } +} diff --git a/auth/auth-cmd/src/test/java/org/onap/aaf/auth/cmd/test/role/JU_ListByNameOnly.java b/auth/auth-cmd/src/test/java/org/onap/aaf/auth/cmd/test/role/JU_ListByNameOnly.java new file mode 100644 index 00000000..a87101d0 --- /dev/null +++ b/auth/auth-cmd/src/test/java/org/onap/aaf/auth/cmd/test/role/JU_ListByNameOnly.java @@ -0,0 +1,73 @@ +/******************************************************************************* + * ============LICENSE_START==================================================== + * * org.onap.aaf + * * =========================================================================== + * * Copyright © 2017 AT&T Intellectual Property. All rights reserved. + * * =========================================================================== + * * 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==================================================== + * * + * * + ******************************************************************************/ +package org.onap.aaf.auth.cmd.test.role; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; + +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.runners.MockitoJUnitRunner; +import org.onap.aaf.auth.cmd.AAFcli; +import org.onap.aaf.auth.cmd.role.List; +import org.onap.aaf.auth.cmd.role.ListByNameOnly; +import org.onap.aaf.auth.cmd.role.Role; +import org.onap.aaf.auth.cmd.test.JU_AAFCli; +import org.onap.aaf.cadi.CadiException; +import org.onap.aaf.cadi.LocatorException; +import org.onap.aaf.misc.env.APIException; + +@RunWith(MockitoJUnitRunner.class) +public class JU_ListByNameOnly { +// +// private static ListByNameOnly lsByName; +// +// @BeforeClass +// public static void setUp () throws NoSuchFieldException, SecurityException, Exception, IllegalAccessException { +// AAFcli cli = JU_AAFCli.getAAfCli(); +// Role role = new Role(cli); +// List ls = new List(role); +// lsByName = new ListByNameOnly(ls); +// } +// +// @Test +// public void exec() { +// try { +// assertEquals(lsByName._exec(0, "add","del","reset","extend","clear", "rename", "create"),500); +// } catch (CadiException e) { +// // TODO Auto-generated catch block +// e.printStackTrace(); +// } catch (APIException e) { +// // TODO Auto-generated catch block +// e.printStackTrace(); +// } catch (LocatorException e) { +// // TODO Auto-generated catch block +// e.printStackTrace(); +// } +// } + + @Test //TODO: Temporary fix AAF-111 + public void netYetTested() { + fail("Tests not yet implemented"); + } +} diff --git a/auth/auth-cmd/src/test/java/org/onap/aaf/auth/cmd/test/role/JU_ListByPerm.java b/auth/auth-cmd/src/test/java/org/onap/aaf/auth/cmd/test/role/JU_ListByPerm.java new file mode 100644 index 00000000..6be99ab0 --- /dev/null +++ b/auth/auth-cmd/src/test/java/org/onap/aaf/auth/cmd/test/role/JU_ListByPerm.java @@ -0,0 +1,73 @@ +/******************************************************************************* + * ============LICENSE_START==================================================== + * * org.onap.aaf + * * =========================================================================== + * * Copyright © 2017 AT&T Intellectual Property. All rights reserved. + * * =========================================================================== + * * 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==================================================== + * * + * * + ******************************************************************************/ +package org.onap.aaf.auth.cmd.test.role; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; + +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.runners.MockitoJUnitRunner; +import org.onap.aaf.auth.cmd.AAFcli; +import org.onap.aaf.auth.cmd.role.List; +import org.onap.aaf.auth.cmd.role.ListByPerm; +import org.onap.aaf.auth.cmd.role.Role; +import org.onap.aaf.auth.cmd.test.JU_AAFCli; +import org.onap.aaf.cadi.CadiException; +import org.onap.aaf.cadi.LocatorException; +import org.onap.aaf.misc.env.APIException; + +@RunWith(MockitoJUnitRunner.class) +public class JU_ListByPerm { + +// private static ListByPerm lsByPerm; +// +// @BeforeClass +// public static void setUp () throws NoSuchFieldException, SecurityException, Exception, IllegalAccessException { +// AAFcli cli = JU_AAFCli.getAAfCli(); +// Role role = new Role(cli); +// List ls = new List(role); +// lsByPerm = new ListByPerm(ls); +// } +// +// @Test +// public void exec() { +// try { +// assertEquals(lsByPerm._exec(0, "add","del","reset","extend","clear", "rename", "create"),500); +// } catch (CadiException e) { +// // TODO Auto-generated catch block +// e.printStackTrace(); +// } catch (APIException e) { +// // TODO Auto-generated catch block +// e.printStackTrace(); +// } catch (LocatorException e) { +// // TODO Auto-generated catch block +// e.printStackTrace(); +// } +// } + + @Test //TODO: Temporary fix AAF-111 + public void netYetTested() { + fail("Tests not yet implemented"); + } +} diff --git a/auth/auth-cmd/src/test/java/org/onap/aaf/auth/cmd/test/role/JU_ListByRole.java b/auth/auth-cmd/src/test/java/org/onap/aaf/auth/cmd/test/role/JU_ListByRole.java new file mode 100644 index 00000000..5739208a --- /dev/null +++ b/auth/auth-cmd/src/test/java/org/onap/aaf/auth/cmd/test/role/JU_ListByRole.java @@ -0,0 +1,73 @@ +/******************************************************************************* + * ============LICENSE_START==================================================== + * * org.onap.aaf + * * =========================================================================== + * * Copyright © 2017 AT&T Intellectual Property. All rights reserved. + * * =========================================================================== + * * 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==================================================== + * * + * * + ******************************************************************************/ +package org.onap.aaf.auth.cmd.test.role; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; + +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.runners.MockitoJUnitRunner; +import org.onap.aaf.auth.cmd.AAFcli; +import org.onap.aaf.auth.cmd.role.List; +import org.onap.aaf.auth.cmd.role.ListByRole; +import org.onap.aaf.auth.cmd.role.Role; +import org.onap.aaf.auth.cmd.test.JU_AAFCli; +import org.onap.aaf.cadi.CadiException; +import org.onap.aaf.cadi.LocatorException; +import org.onap.aaf.misc.env.APIException; + +@RunWith(MockitoJUnitRunner.class) +public class JU_ListByRole { + +// private static ListByRole lsByRole; +// +// @BeforeClass +// public static void setUp () throws NoSuchFieldException, SecurityException, Exception, IllegalAccessException { +// AAFcli cli = JU_AAFCli.getAAfCli(); +// Role role = new Role(cli); +// List ls = new List(role); +// lsByRole = new ListByRole(ls); +// } +// +// @Test +// public void exec() { +// try { +// assertEquals(lsByRole._exec(0, "add","del","reset","extend","clear", "rename", "create"),500); +// } catch (CadiException e) { +// // TODO Auto-generated catch block +// e.printStackTrace(); +// } catch (APIException e) { +// // TODO Auto-generated catch block +// e.printStackTrace(); +// } catch (LocatorException e) { +// // TODO Auto-generated catch block +// e.printStackTrace(); +// } +// } + + @Test //TODO: Temporary fix AAF-111 + public void netYetTested() { + fail("Tests not yet implemented"); + } +} diff --git a/auth/auth-cmd/src/test/java/org/onap/aaf/auth/cmd/test/role/JU_ListByUser.java b/auth/auth-cmd/src/test/java/org/onap/aaf/auth/cmd/test/role/JU_ListByUser.java new file mode 100644 index 00000000..be11e1f7 --- /dev/null +++ b/auth/auth-cmd/src/test/java/org/onap/aaf/auth/cmd/test/role/JU_ListByUser.java @@ -0,0 +1,73 @@ +/******************************************************************************* + * ============LICENSE_START==================================================== + * * org.onap.aaf + * * =========================================================================== + * * Copyright © 2017 AT&T Intellectual Property. All rights reserved. + * * =========================================================================== + * * 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==================================================== + * * + * * + ******************************************************************************/ +package org.onap.aaf.auth.cmd.test.role; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; + +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.runners.MockitoJUnitRunner; +import org.onap.aaf.auth.cmd.AAFcli; +import org.onap.aaf.auth.cmd.role.List; +import org.onap.aaf.auth.cmd.role.ListByUser; +import org.onap.aaf.auth.cmd.role.Role; +import org.onap.aaf.auth.cmd.test.JU_AAFCli; +import org.onap.aaf.cadi.CadiException; +import org.onap.aaf.cadi.LocatorException; +import org.onap.aaf.misc.env.APIException; + +@RunWith(MockitoJUnitRunner.class) +public class JU_ListByUser { +// +// private static ListByUser lsByUser; +// +// @BeforeClass +// public static void setUp () throws NoSuchFieldException, SecurityException, Exception, IllegalAccessException { +// AAFcli cli = JU_AAFCli.getAAfCli(); +// Role role = new Role(cli); +// List ls = new List(role); +// lsByUser = new ListByUser(ls); +// } +// +// @Test +// public void exec() { +// try { +// assertEquals(lsByUser._exec(0, "add","del","reset","extend","clear", "rename", "create"),500); +// } catch (CadiException e) { +// // TODO Auto-generated catch block +// e.printStackTrace(); +// } catch (APIException e) { +// // TODO Auto-generated catch block +// e.printStackTrace(); +// } catch (LocatorException e) { +// // TODO Auto-generated catch block +// e.printStackTrace(); +// } +// } + + @Test //TODO: Temporary fix AAF-111 + public void netYetTested() { + fail("Tests not yet implemented"); + } +} diff --git a/auth/auth-cmd/src/test/java/org/onap/aaf/auth/cmd/test/role/JU_User.java b/auth/auth-cmd/src/test/java/org/onap/aaf/auth/cmd/test/role/JU_User.java new file mode 100644 index 00000000..37cfb304 --- /dev/null +++ b/auth/auth-cmd/src/test/java/org/onap/aaf/auth/cmd/test/role/JU_User.java @@ -0,0 +1,72 @@ +/******************************************************************************* + * ============LICENSE_START==================================================== + * * org.onap.aaf + * * =========================================================================== + * * Copyright © 2017 AT&T Intellectual Property. All rights reserved. + * * =========================================================================== + * * 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==================================================== + * * + * * + ******************************************************************************/ +package org.onap.aaf.auth.cmd.test.role; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; + +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.runners.MockitoJUnitRunner; +import org.onap.aaf.auth.cmd.AAFcli; +import org.onap.aaf.auth.cmd.perm.Perm; +import org.onap.aaf.auth.cmd.role.Role; +import org.onap.aaf.auth.cmd.role.User; +import org.onap.aaf.auth.cmd.test.JU_AAFCli; +import org.onap.aaf.cadi.CadiException; +import org.onap.aaf.cadi.LocatorException; +import org.onap.aaf.misc.env.APIException; + +@RunWith(MockitoJUnitRunner.class) +public class JU_User { + +// private static User user; +// +// @BeforeClass +// public static void setUp () throws NoSuchFieldException, SecurityException, Exception, IllegalAccessException { +// AAFcli cli = JU_AAFCli.getAAfCli(); +// Role role = new Role(cli); +// user = new User(role); +// } +// +// @Test +// public void exec() { +// try { +// assertEquals(user._exec(0, "add","del","reset","extend","clear", "rename", "create"),500); +// } catch (CadiException e) { +// // TODO Auto-generated catch block +// e.printStackTrace(); +// } catch (APIException e) { +// // TODO Auto-generated catch block +// e.printStackTrace(); +// } catch (LocatorException e) { +// // TODO Auto-generated catch block +// e.printStackTrace(); +// } +// } + + @Test //TODO: Temporary fix AAF-111 + public void netYetTested() { + fail("Tests not yet implemented"); + } +} diff --git a/auth/auth-cmd/src/test/java/org/onap/aaf/auth/cmd/test/user/JU_Cred.java b/auth/auth-cmd/src/test/java/org/onap/aaf/auth/cmd/test/user/JU_Cred.java new file mode 100644 index 00000000..f191ef65 --- /dev/null +++ b/auth/auth-cmd/src/test/java/org/onap/aaf/auth/cmd/test/user/JU_Cred.java @@ -0,0 +1,124 @@ +/******************************************************************************* + * ============LICENSE_START==================================================== + * * org.onap.aaf + * * =========================================================================== + * * Copyright © 2017 AT&T Intellectual Property. All rights reserved. + * * =========================================================================== + * * 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==================================================== + * * + * * + ******************************************************************************/ +package org.onap.aaf.auth.cmd.test.user; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import java.io.FileNotFoundException; +import java.io.PrintWriter; + +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mockito; +import org.mockito.runners.MockitoJUnitRunner; +import org.onap.aaf.auth.cmd.AAFcli; +import org.onap.aaf.auth.cmd.Cmd; +import org.onap.aaf.auth.cmd.user.Cred; +import org.onap.aaf.auth.cmd.user.User; +import org.onap.aaf.auth.env.AuthzEnv; +import org.onap.aaf.cadi.CadiException; +import org.onap.aaf.cadi.LocatorException; +import org.onap.aaf.misc.env.APIException; + +@RunWith(MockitoJUnitRunner.class) +public class JU_Cred { + + private static Cred testCred; + private static User testUser; + private static AuthzEnv env; + + + @BeforeClass + public static void setUp() throws FileNotFoundException, APIException { + + testCred = mock(Cred.class); + testUser = mock(User.class); + env = mock(AuthzEnv.class); + Mockito.when(env.getProperty(Cmd.STARTDATE,null)).thenReturn(null); + Mockito.when(env.getProperty(Cmd.ENDDATE,null)).thenReturn(null); + + } + + @Test + public void exec() throws CadiException, APIException, LocatorException, FileNotFoundException { + boolean isNullpointer=false; + AAFcli aaFcli= new AAFcli(env, new PrintWriter("temp"), null, null, null); + User user= new User(aaFcli); + Cred testCred= new Cred(user); + try { + testCred._exec(0, "add", "del", "reset", "extend"); + } catch (Exception e) { + isNullpointer=true; + } + assertEquals(isNullpointer, true); + } + + + @Test + public void exec_add() { + try { + assertNotNull(testCred._exec(0, "zeroed","add","del","reset","extend")); + } catch (CadiException | APIException | LocatorException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + + } + + @Test + public void exec_del() { + try { + assertNotNull(testCred._exec(1, "zeroed","add","del","reset","extend")); + } catch (CadiException | APIException | LocatorException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + + } + + @Test + public void exec_reset() { + try { + assertNotNull(testCred._exec(2, "zeroed","add","del","reset","extend")); + } catch (CadiException | APIException | LocatorException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + + } + + @Test + public void exec_extend() { + try { + assertNotNull(testCred._exec(3, "zeroed","add","del","reset","extend")); + } catch (CadiException | APIException | LocatorException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + + } + +} diff --git a/auth/auth-cmd/src/test/java/org/onap/aaf/auth/cmd/test/user/JU_Delg.java b/auth/auth-cmd/src/test/java/org/onap/aaf/auth/cmd/test/user/JU_Delg.java new file mode 100644 index 00000000..f129149d --- /dev/null +++ b/auth/auth-cmd/src/test/java/org/onap/aaf/auth/cmd/test/user/JU_Delg.java @@ -0,0 +1,79 @@ +/******************************************************************************* + * ============LICENSE_START==================================================== + * * org.onap.aaf + * * =========================================================================== + * * Copyright © 2017 AT&T Intellectual Property. All rights reserved. + * * =========================================================================== + * * 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==================================================== + * * + * * + ******************************************************************************/ +package org.onap.aaf.auth.cmd.test.user; + +import static org.mockito.Mockito.mock; +import static org.junit.Assert.*; + +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.runners.MockitoJUnitRunner; +import org.onap.aaf.auth.cmd.user.Delg; +import org.onap.aaf.auth.cmd.user.User; +import org.onap.aaf.cadi.CadiException; +import org.onap.aaf.cadi.LocatorException; +import org.onap.aaf.misc.env.APIException; + +@RunWith(MockitoJUnitRunner.class) +public class JU_Delg { + + private static User testUser; + private static Delg delg; + + @BeforeClass + public static void setUp() throws APIException { + testUser = mock(User.class); + delg = mock(Delg.class); + } + + @Test + public void exec_add() { + try { + assertEquals(delg._exec(0, "zero","add","upd","del"), 0); + } catch (CadiException | APIException | LocatorException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + + @Test + public void exec_upd() { + try { + assertEquals(delg._exec(1, "zero","add","upd","del"), 0); + } catch (CadiException | APIException | LocatorException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + + @Test + public void exec_del() { + try { + assertEquals(delg._exec(2, "zero","add","upd","del"), 0); + } catch (CadiException | APIException | LocatorException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + +} diff --git a/auth/auth-cmd/src/test/java/org/onap/aaf/auth/cmd/test/user/JU_ListActivity.java b/auth/auth-cmd/src/test/java/org/onap/aaf/auth/cmd/test/user/JU_ListActivity.java new file mode 100644 index 00000000..5f1cfb3b --- /dev/null +++ b/auth/auth-cmd/src/test/java/org/onap/aaf/auth/cmd/test/user/JU_ListActivity.java @@ -0,0 +1,74 @@ +/******************************************************************************* + * ============LICENSE_START==================================================== + * * org.onap.aaf + * * =========================================================================== + * * Copyright © 2017 AT&T Intellectual Property. All rights reserved. + * * =========================================================================== + * * 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==================================================== + * * + * * + ******************************************************************************/ +package org.onap.aaf.auth.cmd.test.user; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; + +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.runners.MockitoJUnitRunner; +import org.onap.aaf.auth.cmd.AAFcli; +import org.onap.aaf.auth.cmd.test.JU_AAFCli; +import org.onap.aaf.auth.cmd.user.List; +import org.onap.aaf.auth.cmd.user.ListActivity; +import org.onap.aaf.auth.cmd.user.User; +import org.onap.aaf.cadi.CadiException; +import org.onap.aaf.cadi.LocatorException; +import org.onap.aaf.misc.env.APIException; + +@RunWith(MockitoJUnitRunner.class) +public class JU_ListActivity { + +// private static ListActivity lsActivity; +// +// @BeforeClass +// public static void setUp () throws NoSuchFieldException, SecurityException, Exception, IllegalAccessException { +// AAFcli cli = JU_AAFCli.getAAfCli(); +// User usr = new User(cli); +// List parent = new List(usr); +// lsActivity = new ListActivity(parent); +// +// } +// +// @Test +// public void exec() { +// try { +// assertEquals(lsActivity._exec(0, "add","del","reset","extend","clear", "rename", "create"),500); +// } catch (CadiException e) { +// +// e.printStackTrace(); +// } catch (APIException e) { +// +// e.printStackTrace(); +// } catch (LocatorException e) { +// +// e.printStackTrace(); +// } +// } + + @Test //TODO: Temporary fix AAF-111 + public void netYetTested() { + fail("Tests not yet implemented"); + } +} diff --git a/auth/auth-cmd/src/test/java/org/onap/aaf/auth/cmd/test/user/JU_ListApprovals.java b/auth/auth-cmd/src/test/java/org/onap/aaf/auth/cmd/test/user/JU_ListApprovals.java new file mode 100644 index 00000000..196cd028 --- /dev/null +++ b/auth/auth-cmd/src/test/java/org/onap/aaf/auth/cmd/test/user/JU_ListApprovals.java @@ -0,0 +1,74 @@ +/******************************************************************************* + * ============LICENSE_START==================================================== + * * org.onap.aaf + * * =========================================================================== + * * Copyright © 2017 AT&T Intellectual Property. All rights reserved. + * * =========================================================================== + * * 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==================================================== + * * + * * + ******************************************************************************/ +package org.onap.aaf.auth.cmd.test.user; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; + +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.runners.MockitoJUnitRunner; +import org.onap.aaf.auth.cmd.AAFcli; +import org.onap.aaf.auth.cmd.test.JU_AAFCli; +import org.onap.aaf.auth.cmd.user.List; +import org.onap.aaf.auth.cmd.user.ListApprovals; +import org.onap.aaf.auth.cmd.user.User; +import org.onap.aaf.cadi.CadiException; +import org.onap.aaf.cadi.LocatorException; +import org.onap.aaf.misc.env.APIException; + +@RunWith(MockitoJUnitRunner.class) +public class JU_ListApprovals { + +// private static ListApprovals lsApprovals; +// +// @BeforeClass +// public static void setUp () throws NoSuchFieldException, SecurityException, Exception, IllegalAccessException { +// AAFcli cli = JU_AAFCli.getAAfCli(); +// User usr = new User(cli); +// List parent = new List(usr); +// lsApprovals = new ListApprovals(parent); +// +// } +// +// @Test +// public void exec() { +// try { +// assertEquals(lsApprovals._exec(0, "add","del","reset","extend","clear", "rename", "create"),500); +// } catch (CadiException e) { +// +// e.printStackTrace(); +// } catch (APIException e) { +// +// e.printStackTrace(); +// } catch (LocatorException e) { +// +// e.printStackTrace(); +// } +// } + + @Test //TODO: Temporary fix AAF-111 + public void netYetTested() { + fail("Tests not yet implemented"); + } +} diff --git a/auth/auth-cmd/src/test/java/org/onap/aaf/auth/cmd/test/user/JU_ListDelegates.java b/auth/auth-cmd/src/test/java/org/onap/aaf/auth/cmd/test/user/JU_ListDelegates.java new file mode 100644 index 00000000..3e11357f --- /dev/null +++ b/auth/auth-cmd/src/test/java/org/onap/aaf/auth/cmd/test/user/JU_ListDelegates.java @@ -0,0 +1,74 @@ +/******************************************************************************* + * ============LICENSE_START==================================================== + * * org.onap.aaf + * * =========================================================================== + * * Copyright © 2017 AT&T Intellectual Property. All rights reserved. + * * =========================================================================== + * * 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==================================================== + * * + * * + ******************************************************************************/ +package org.onap.aaf.auth.cmd.test.user; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; + +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.runners.MockitoJUnitRunner; +import org.onap.aaf.auth.cmd.AAFcli; +import org.onap.aaf.auth.cmd.test.JU_AAFCli; +import org.onap.aaf.auth.cmd.user.List; +import org.onap.aaf.auth.cmd.user.ListDelegates; +import org.onap.aaf.auth.cmd.user.User; +import org.onap.aaf.cadi.CadiException; +import org.onap.aaf.cadi.LocatorException; +import org.onap.aaf.misc.env.APIException; + +@RunWith(MockitoJUnitRunner.class) +public class JU_ListDelegates { + +// private static ListDelegates lsDelegates; +// +// @BeforeClass +// public static void setUp () throws NoSuchFieldException, SecurityException, Exception, IllegalAccessException { +// AAFcli cli = JU_AAFCli.getAAfCli(); +// User usr = new User(cli); +// List parent = new List(usr); +// lsDelegates = new ListDelegates(parent); +// +// } +// +// @Test +// public void exec() { +// try { +// assertEquals(lsDelegates._exec(0, "add","del","reset","extend","clear", "rename", "create"),500); +// } catch (CadiException e) { +// +// e.printStackTrace(); +// } catch (APIException e) { +// +// e.printStackTrace(); +// } catch (LocatorException e) { +// +// e.printStackTrace(); +// } +// } + + @Test //TODO: Temporary fix AAF-111 + public void netYetTested() { + fail("Tests not yet implemented"); + } +} diff --git a/auth/auth-cmd/src/test/java/org/onap/aaf/auth/cmd/test/user/JU_ListForCreds.java b/auth/auth-cmd/src/test/java/org/onap/aaf/auth/cmd/test/user/JU_ListForCreds.java new file mode 100644 index 00000000..cdd8fe87 --- /dev/null +++ b/auth/auth-cmd/src/test/java/org/onap/aaf/auth/cmd/test/user/JU_ListForCreds.java @@ -0,0 +1,74 @@ +/******************************************************************************* + * ============LICENSE_START==================================================== + * * org.onap.aaf + * * =========================================================================== + * * Copyright © 2017 AT&T Intellectual Property. All rights reserved. + * * =========================================================================== + * * 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==================================================== + * * + * * + ******************************************************************************/ +package org.onap.aaf.auth.cmd.test.user; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; + +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.runners.MockitoJUnitRunner; +import org.onap.aaf.auth.cmd.AAFcli; +import org.onap.aaf.auth.cmd.test.JU_AAFCli; +import org.onap.aaf.auth.cmd.user.List; +import org.onap.aaf.auth.cmd.user.ListForCreds; +import org.onap.aaf.auth.cmd.user.User; +import org.onap.aaf.cadi.CadiException; +import org.onap.aaf.cadi.LocatorException; +import org.onap.aaf.misc.env.APIException; + +@RunWith(MockitoJUnitRunner.class) +public class JU_ListForCreds { +// +// private static ListForCreds lsForCreds; +// +// @BeforeClass +// public static void setUp () throws NoSuchFieldException, SecurityException, Exception, IllegalAccessException { +// AAFcli cli = JU_AAFCli.getAAfCli(); +// User usr = new User(cli); +// List parent = new List(usr); +// lsForCreds = new ListForCreds(parent); +// +// } +// +// @Test +// public void exec() { +// try { +// assertEquals(lsForCreds._exec(0, "add","del","reset","extend","clear", "rename", "create"),500); +// } catch (CadiException e) { +// +// e.printStackTrace(); +// } catch (APIException e) { +// +// e.printStackTrace(); +// } catch (LocatorException e) { +// +// e.printStackTrace(); +// } +// } + + @Test //TODO: Temporary fix AAF-111 + public void netYetTested() { + fail("Tests not yet implemented"); + } +} diff --git a/auth/auth-cmd/src/test/java/org/onap/aaf/auth/cmd/test/user/JU_ListForPermission.java b/auth/auth-cmd/src/test/java/org/onap/aaf/auth/cmd/test/user/JU_ListForPermission.java new file mode 100644 index 00000000..7d6af44b --- /dev/null +++ b/auth/auth-cmd/src/test/java/org/onap/aaf/auth/cmd/test/user/JU_ListForPermission.java @@ -0,0 +1,74 @@ +/******************************************************************************* + * ============LICENSE_START==================================================== + * * org.onap.aaf + * * =========================================================================== + * * Copyright © 2017 AT&T Intellectual Property. All rights reserved. + * * =========================================================================== + * * 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==================================================== + * * + * * + ******************************************************************************/ +package org.onap.aaf.auth.cmd.test.user; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; + +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.runners.MockitoJUnitRunner; +import org.onap.aaf.auth.cmd.AAFcli; +import org.onap.aaf.auth.cmd.test.JU_AAFCli; +import org.onap.aaf.auth.cmd.user.List; +import org.onap.aaf.auth.cmd.user.ListForPermission; +import org.onap.aaf.auth.cmd.user.User; +import org.onap.aaf.cadi.CadiException; +import org.onap.aaf.cadi.LocatorException; +import org.onap.aaf.misc.env.APIException; + +@RunWith(MockitoJUnitRunner.class) +public class JU_ListForPermission { +// +// private static ListForPermission lsForPermission; +// +// @BeforeClass +// public static void setUp () throws NoSuchFieldException, SecurityException, Exception, IllegalAccessException { +// AAFcli cli = JU_AAFCli.getAAfCli(); +// User usr = new User(cli); +// List parent = new List(usr); +// lsForPermission = new ListForPermission(parent); +// +// } +// +// @Test +// public void exec() { +// try { +// assertEquals(lsForPermission._exec(0, "add","del","reset","extend","clear", "rename", "create"),500); +// } catch (CadiException e) { +// +// e.printStackTrace(); +// } catch (APIException e) { +// +// e.printStackTrace(); +// } catch (LocatorException e) { +// +// e.printStackTrace(); +// } +// } + + @Test //TODO: Temporary fix AAF-111 + public void netYetTested() { + fail("Tests not yet implemented"); + } +} diff --git a/auth/auth-cmd/src/test/java/org/onap/aaf/auth/cmd/test/user/JU_ListForRoles.java b/auth/auth-cmd/src/test/java/org/onap/aaf/auth/cmd/test/user/JU_ListForRoles.java new file mode 100644 index 00000000..74f57cfc --- /dev/null +++ b/auth/auth-cmd/src/test/java/org/onap/aaf/auth/cmd/test/user/JU_ListForRoles.java @@ -0,0 +1,74 @@ +/******************************************************************************* + * ============LICENSE_START==================================================== + * * org.onap.aaf + * * =========================================================================== + * * Copyright © 2017 AT&T Intellectual Property. All rights reserved. + * * =========================================================================== + * * 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==================================================== + * * + * * + ******************************************************************************/ +package org.onap.aaf.auth.cmd.test.user; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; + +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.runners.MockitoJUnitRunner; +import org.onap.aaf.auth.cmd.AAFcli; +import org.onap.aaf.auth.cmd.test.JU_AAFCli; +import org.onap.aaf.auth.cmd.user.List; +import org.onap.aaf.auth.cmd.user.ListForRoles; +import org.onap.aaf.auth.cmd.user.User; +import org.onap.aaf.cadi.CadiException; +import org.onap.aaf.cadi.LocatorException; +import org.onap.aaf.misc.env.APIException; + +@RunWith(MockitoJUnitRunner.class) +public class JU_ListForRoles { + +// private static ListForRoles lsForRoles; +// +// @BeforeClass +// public static void setUp () throws NoSuchFieldException, SecurityException, Exception, IllegalAccessException { +// AAFcli cli = JU_AAFCli.getAAfCli(); +// User usr = new User(cli); +// List parent = new List(usr); +// lsForRoles = new ListForRoles(parent); +// +// } +// +// @Test +// public void exec() { +// try { +// assertEquals(lsForRoles._exec(0, "add","del","reset","extend","clear", "rename", "create"),500); +// } catch (CadiException e) { +// +// e.printStackTrace(); +// } catch (APIException e) { +// +// e.printStackTrace(); +// } catch (LocatorException e) { +// +// e.printStackTrace(); +// } +// } + + @Test //TODO: Temporary fix AAF-111 + public void netYetTested() { + fail("Tests not yet implemented"); + } +} diff --git a/auth/auth-cmd/src/test/java/org/onap/aaf/auth/cmd/test/user/JU_Role.java b/auth/auth-cmd/src/test/java/org/onap/aaf/auth/cmd/test/user/JU_Role.java new file mode 100644 index 00000000..230be45e --- /dev/null +++ b/auth/auth-cmd/src/test/java/org/onap/aaf/auth/cmd/test/user/JU_Role.java @@ -0,0 +1,72 @@ +/******************************************************************************* + * ============LICENSE_START==================================================== + * * org.onap.aaf + * * =========================================================================== + * * Copyright © 2017 AT&T Intellectual Property. All rights reserved. + * * =========================================================================== + * * 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==================================================== + * * + * * + ******************************************************************************/ +package org.onap.aaf.auth.cmd.test.user; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; + +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.runners.MockitoJUnitRunner; +import org.onap.aaf.auth.cmd.AAFcli; +import org.onap.aaf.auth.cmd.test.JU_AAFCli; +import org.onap.aaf.auth.cmd.user.Role; +import org.onap.aaf.auth.cmd.user.User; +import org.onap.aaf.cadi.CadiException; +import org.onap.aaf.cadi.LocatorException; +import org.onap.aaf.misc.env.APIException; + +@RunWith(MockitoJUnitRunner.class) +public class JU_Role { + +// private static Role role; +// +// @BeforeClass +// public static void setUp () throws NoSuchFieldException, SecurityException, Exception, IllegalAccessException { +// AAFcli cli = JU_AAFCli.getAAfCli(); +// User usr = new User(cli); +// role = new Role(usr); +// +// } +// +// @Test +// public void exec() { +// try { +// assertEquals(role._exec(0, "add","del","reset","extend","clear", "rename", "create"),500); +// } catch (CadiException e) { +// +// e.printStackTrace(); +// } catch (APIException e) { +// +// e.printStackTrace(); +// } catch (LocatorException e) { +// +// e.printStackTrace(); +// } +// } + + @Test //TODO: Temporary fix AAF-111 + public void netYetTested() { + fail("Tests not yet implemented"); + } +} diff --git a/auth/auth-core/.gitignore b/auth/auth-core/.gitignore new file mode 100644 index 00000000..8f0ac9b9 --- /dev/null +++ b/auth/auth-core/.gitignore @@ -0,0 +1,5 @@ +/.settings +/bin +/target +/.classpath +/.project diff --git a/auth/auth-core/pom.xml b/auth/auth-core/pom.xml new file mode 100644 index 00000000..a8002024 --- /dev/null +++ b/auth/auth-core/pom.xml @@ -0,0 +1,104 @@ + + + + 4.0.0 + + org.onap.aaf.auth + parent + 2.1.0-SNAPSHOT + ../pom.xml + + + aaf-auth-core + AAF Auth Core + Core Library for AAF Auth Components + jar + + + + Jonathan Gathman + jonathan.gathman@att.com + ATT + + Architect + Lead Developer + + + + Gabe Maurer + gabe.maurer@att.com + ATT + + Developer + + + + Ian Howell + ian.howell@att.com + ATT + + Developer + + + + + + + + org.onap.aaf.misc + aaf-misc-env + + + org.onap.aaf.cadi + aaf-cadi-aaf + + + + javax.servlet + servlet-api + + + + org.onap.aaf.misc + aaf-misc-log4j + + + + org.onap.aaf.cadi + aaf-cadi-core + + + + org.eclipse.jetty + jetty-servlet + compile + + + + org.eclipse.jetty + jetty-jmx + compile + + + + diff --git a/auth/auth-core/src/main/java/org/onap/aaf/auth/cache/Cache.java b/auth/auth-core/src/main/java/org/onap/aaf/auth/cache/Cache.java new file mode 100644 index 00000000..17368031 --- /dev/null +++ b/auth/auth-core/src/main/java/org/onap/aaf/auth/cache/Cache.java @@ -0,0 +1,200 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.cache; + +import java.util.ArrayList; +import java.util.Date; +import java.util.HashMap; +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.concurrent.ConcurrentHashMap; +import java.util.logging.Level; + +import org.onap.aaf.misc.env.Env; +import org.onap.aaf.misc.env.Trans; + +/** + * Create and maintain a Map of Maps used for Caching + * + * @author Jonathan + * + * @param + * @param + */ +public class Cache { + private static Clean clean; + private static Timer cleanseTimer; + + public static final String CACHE_HIGH_COUNT = "CACHE_HIGH_COUNT"; + public static final String CACHE_CLEAN_INTERVAL = "CACHE_CLEAN_INTERVAL"; +// public static final String CACHE_MIN_REFRESH_INTERVAL = "CACHE_MIN_REFRESH_INTERVAL"; + + private static final Map> cacheMap; + + static { + cacheMap = new HashMap>(); + } + + /** + * Dated Class - store any Data with timestamp + * + * @author Jonathan + * + */ + public final static class Dated { + public Date timestamp; + public List data; + private long expireIn; + + public Dated(List data, long expireIn) { + timestamp = new Date(System.currentTimeMillis()+expireIn); + this.data = data; + this.expireIn = expireIn; + } + + public Dated(T t, long expireIn) { + timestamp = new Date(System.currentTimeMillis()+expireIn); + ArrayList al = new ArrayList(1); + al.add(t); + data = al; + this.expireIn = expireIn; + } + + public void touch() { + timestamp = new Date(System.currentTimeMillis()+expireIn); + } + } + + public static Map obtain(String key) { + Map m = cacheMap.get(key); + if(m==null) { + m = new ConcurrentHashMap(); + synchronized(cacheMap) { + cacheMap.put(key, m); + } + } + return m; + } + + /** + * 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. + * + * @author Jonathan + * + */ + private final static class Clean extends TimerTask { + private final Env env; + private Set set; + + // 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; + + public Clean(Env env, long cleanInterval, int highCount) { + this.env = env; + high = highCount; + timeInterval = cleanInterval; + advance = 0; + set = new HashSet(); + } + + public synchronized void add(String key) { + set.add(key); + } + + public void run() { + int count = 0; + int total = 0; + // look at now. If we need to expire more by increasing "now" by "advance" + Date now = new Date(System.currentTimeMillis() + advance); + + + for(String name : set) { + Map map = cacheMap.get(name); + if(map!=null) for(Map.Entry me : map.entrySet()) { + ++total; + if(me.getValue().timestamp.before(now)) { + map.remove(me.getKey()); + ++count; + } + } +// if(count>0) { +// env.info().log(Level.INFO, "Cache removed",count,"expired",name,"Elements"); +// } + } + + if(count>0) { + env.info().log(Level.INFO, "Cache removed",count,"expired Cached Elements out of", total); + } + + // 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)); + } + } + } + + public static synchronized void startCleansing(Env env, String ... keys) { + if(cleanseTimer==null) { + cleanseTimer = new Timer("Cache Cleanup Timer"); + int cleanInterval = Integer.parseInt(env.getProperty(CACHE_CLEAN_INTERVAL,"60000")); // 1 minute clean cycles + int highCount = Integer.parseInt(env.getProperty(CACHE_HIGH_COUNT,"5000")); + cleanseTimer.schedule(clean = new Clean(env, cleanInterval, highCount), cleanInterval, cleanInterval); + } + + for(String key : keys) { + clean.add(key); + } + } + + public static void stopTimer() { + if(cleanseTimer!=null) { + cleanseTimer.cancel(); + cleanseTimer = null; + } + } + + public static void addShutdownHook() { + Runtime.getRuntime().addShutdownHook(new Thread() { + @Override + public void run() { + Cache.stopTimer(); + } + }); + } + +} diff --git a/auth/auth-core/src/main/java/org/onap/aaf/auth/common/Define.java b/auth/auth-core/src/main/java/org/onap/aaf/auth/common/Define.java new file mode 100644 index 00000000..6f0ea084 --- /dev/null +++ b/auth/auth-core/src/main/java/org/onap/aaf/auth/common/Define.java @@ -0,0 +1,82 @@ +/******************************************************************************* + * ============LICENSE_START==================================================== + * * org.onap.aaf + * * =========================================================================== + * * Copyright © 2017 AT&T Intellectual Property. All rights reserved. + * * =========================================================================== + * * 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==================================================== + * * + * * + ******************************************************************************/ +package org.onap.aaf.auth.common; + +import java.util.Map.Entry; + +import org.onap.aaf.cadi.Access; +import org.onap.aaf.cadi.CadiException; +import org.onap.aaf.cadi.Access.Level; +import org.onap.aaf.cadi.config.Config; + +public class Define { + private static String ROOT_NS = null; + private static String ROOT_COMPANY = null; + + private final static String MSG = ".set(Access access) must be called before use"; + public static final CharSequence ROOT_NS_TAG = "AAF_NS"; // use for certain Replacements in Location + private static final String ROOT_NS_TAG_DOT = ROOT_NS_TAG +"."; + + public static String ROOT_NS() { + if(ROOT_NS==null) { + throw new RuntimeException(Define.class.getName() + MSG); + } + return ROOT_NS; + } + + public static String ROOT_COMPANY() { + if(ROOT_NS==null) { + throw new RuntimeException(Define.class.getName() + MSG); + } + return ROOT_COMPANY; + } + + public static void set(Access access) throws CadiException { + ROOT_NS = access.getProperty(Config.AAF_ROOT_NS,"org.onap.aaf"); + ROOT_COMPANY = access.getProperty(Config.AAF_ROOT_COMPANY,null); + if(ROOT_COMPANY==null) { + int last = ROOT_NS.lastIndexOf('.'); + if(last>=0) { + ROOT_COMPANY = ROOT_NS.substring(0, last); + } else { + throw new CadiException(Config.AAF_ROOT_COMPANY + " or " + Config.AAF_ROOT_NS + " property with 3 positions is required."); + } + } + + for( Entry es : access.getProperties().entrySet()) { + if(es.getKey().toString().startsWith(ROOT_NS_TAG_DOT)) { + access.getProperties().setProperty(es.getKey().toString(),varReplace(es.getValue().toString())); + } + } + + access.printf(Level.INIT,"AAF Root NS is %s, and AAF Company Root is %s",ROOT_NS,ROOT_COMPANY); + } + + public static String varReplace(final String potential) { + if(potential.startsWith(ROOT_NS_TAG_DOT)) { + return ROOT_NS + potential.substring(6); + } else { + return potential; + } + } + +} diff --git a/auth/auth-core/src/main/java/org/onap/aaf/auth/env/AuthzEnv.java b/auth/auth-core/src/main/java/org/onap/aaf/auth/env/AuthzEnv.java new file mode 100644 index 00000000..0bbe079e --- /dev/null +++ b/auth/auth-core/src/main/java/org/onap/aaf/auth/env/AuthzEnv.java @@ -0,0 +1,310 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.env; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.Properties; + +import org.onap.aaf.cadi.Access; +import org.onap.aaf.cadi.CadiException; +import org.onap.aaf.cadi.PropAccess; +import org.onap.aaf.cadi.Symm; +import org.onap.aaf.cadi.PropAccess.LogIt; +import org.onap.aaf.cadi.config.Config; +import org.onap.aaf.misc.env.APIException; +import org.onap.aaf.misc.env.Decryptor; +import org.onap.aaf.misc.env.Encryptor; +import org.onap.aaf.misc.env.impl.Log4JLogTarget; +import org.onap.aaf.misc.env.log4j.LogFileNamer; +import org.onap.aaf.misc.rosetta.env.RosettaEnv; + + +/** + * AuthzEnv is the Env tailored to Authz Service + * + * Most of it is derived from RosettaEnv, but it also implements Access, which + * is an Interface that Allows CADI to interact with Container Logging + * + * @author Jonathan + * + */ +public class AuthzEnv extends RosettaEnv implements Access { + private long[] times = new long[20]; + private int idx = 0; + private PropAccess access; + + public AuthzEnv() { + super(); + _init(new PropAccess()); + } + + public AuthzEnv(String ... args) { + super(); + _init(new PropAccess(args)); + } + + public AuthzEnv(Properties props) { + super(); + _init(new PropAccess(props)); + } + + + public AuthzEnv(PropAccess pa) { + super(); + _init(pa); + } + + private final void _init(PropAccess pa) { + access = pa; + times = new long[20]; + idx = 0; + } + + private class Log4JLogit implements LogIt { + + @Override + public void push(Level level, Object... elements) { + switch(level) { + case AUDIT: + audit.log(elements); + break; + case DEBUG: + debug.log(elements); + break; + case ERROR: + error.log(elements); + break; + case INFO: + info.log(elements); + break; + case INIT: + init.log(elements); + break; + case NONE: + break; + case WARN: + warn.log(elements); + break; + } + + } + + } + + @Override + public AuthzTransImpl newTrans() { + synchronized(this) { + times[idx]=System.currentTimeMillis(); + if(++idx>=times.length)idx=0; + } + return new AuthzTransImpl(this); + } + + /** + * Create a Trans, but do not include in Weighted Average + * @return + */ + public AuthzTrans newTransNoAvg() { + return new AuthzTransImpl(this); + } + + public long transRate() { + int count = 0; + long pot = 0; + long prev = 0; + for(int i=idx;i0) { + if(prev>0) { + ++count; + pot += times[i]-prev; + } + prev = times[i]; + } + } + for(int i=0;i0) { + if(prev>0) { + ++count; + pot += times[i]-prev; + } + prev = times[i]; + } + } + + return count==0?300000L:pot/count; // Return Weighted Avg, or 5 mins, if none avail. + } + + @Override + public ClassLoader classLoader() { + return getClass().getClassLoader(); + } + + @Override + public void load(InputStream is) throws IOException { + access.load(is); + } + + @Override + public void log(Level lvl, Object... msgs) { + access.log(lvl, msgs); + } + + @Override + public void log(Exception e, Object... msgs) { + access.log(e,msgs); + } + + @Override + public void printf(Level level, String fmt, Object... elements) { + access.printf(level, fmt, elements); + } + + /* (non-Javadoc) + * @see org.onap.aaf.cadi.Access#willLog(org.onap.aaf.cadi.Access.Level) + */ + @Override + public boolean willLog(Level level) { + return access.willLog(level); + } + + @Override + public void setLogLevel(Level level) { + access.setLogLevel(level); + } + + public void setLog4JNames(String path, String root, String _service, String _audit, String _init, String _trace) throws APIException { + LogFileNamer lfn = new LogFileNamer(root); + if(_service==null) { + throw new APIException("AuthzEnv.setLog4JNames \"_service\" required (as default). Others can be null"); + } + String service=_service=lfn.setAppender(_service); // when name is split, i.e. authz|service, the Appender is "authz", and "service" + String audit=_audit==null?service:lfn.setAppender(_audit); // is part of the log-file name + String init=_init==null?service:lfn.setAppender(_init); + String trace=_trace==null?service:lfn.setAppender(_trace); + //TODO Validate path on Classpath + lfn.configure(path); + super.fatal = new Log4JLogTarget(service,org.apache.log4j.Level.FATAL); + super.error = new Log4JLogTarget(service,org.apache.log4j.Level.ERROR); + super.warn = new Log4JLogTarget(service,org.apache.log4j.Level.WARN); + super.audit = new Log4JLogTarget(audit,org.apache.log4j.Level.WARN); + super.init = new Log4JLogTarget(init,org.apache.log4j.Level.WARN); + super.info = new Log4JLogTarget(service,org.apache.log4j.Level.INFO); + super.debug = new Log4JLogTarget(service,org.apache.log4j.Level.DEBUG); + super.trace = new Log4JLogTarget(trace,org.apache.log4j.Level.TRACE); + + access.set(new Log4JLogit()); + } + + private static final byte[] ENC="enc:".getBytes(); + public String decrypt(String encrypted, final boolean anytext) throws IOException { + if(encrypted==null) { + throw new IOException("Password to be decrypted is null"); + } + if(anytext || encrypted.startsWith("enc:")) { + if(decryptor.equals(Decryptor.NULL) && getProperty(Config.CADI_KEYFILE)!=null) { + final Symm s; + try { + s = Symm.obtain(this); + } catch (CadiException e1) { + throw new IOException(e1); + } + decryptor = new Decryptor() { + private Symm symm = s; + @Override + public String decrypt(String encrypted) { + try { + return (encrypted!=null && (anytext || encrypted.startsWith(Symm.ENC))) + ? symm.depass(encrypted) + : encrypted; + } catch (IOException e) { + return ""; + } + } + }; + encryptor = new Encryptor() { + @Override + public String encrypt(String data) { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + try { + baos.write(ENC); + return "enc:"+s.enpass(data); + } catch (IOException e) { + return ""; + } + } + + }; + } + return decryptor.decrypt(encrypted); + } else { + return encrypted; + } + } + + /* (non-Javadoc) + * @see org.onap.aaf.misc.env.impl.BasicEnv#getProperty(java.lang.String) + */ + @Override + public String getProperty(String key) { + return access.getProperty(key); + } + + /* (non-Javadoc) + * @see org.onap.aaf.misc.env.impl.BasicEnv#getProperties(java.lang.String[]) + */ + @Override + public Properties getProperties(String... filter) { + return access.getProperties(); + } + + /* (non-Javadoc) + * @see org.onap.aaf.misc.env.impl.BasicEnv#getProperty(java.lang.String, java.lang.String) + */ + @Override + public String getProperty(String key, String defaultValue) { + return access.getProperty(key, defaultValue); + } + + /* (non-Javadoc) + * @see org.onap.aaf.misc.env.impl.BasicEnv#setProperty(java.lang.String, java.lang.String) + */ + @Override + public String setProperty(String key, String value) { + access.setProperty(key, value); + return value; + } + + public PropAccess access() { + return access; + } + + /* (non-Javadoc) + * @see org.onap.aaf.cadi.Access#getProperties() + */ + @Override + public Properties getProperties() { + return access.getProperties(); + }; + +} diff --git a/auth/auth-core/src/main/java/org/onap/aaf/auth/env/AuthzTrans.java b/auth/auth-core/src/main/java/org/onap/aaf/auth/env/AuthzTrans.java new file mode 100644 index 00000000..a38a3e20 --- /dev/null +++ b/auth/auth-core/src/main/java/org/onap/aaf/auth/env/AuthzTrans.java @@ -0,0 +1,78 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.env; + +import java.util.Date; + +import javax.servlet.http.HttpServletRequest; + +import org.onap.aaf.auth.org.Organization; +import org.onap.aaf.cadi.Lur; +import org.onap.aaf.cadi.Permission; +import org.onap.aaf.cadi.principal.TaggedPrincipal; +import org.onap.aaf.misc.env.LogTarget; +import org.onap.aaf.misc.env.TransStore; + +public interface AuthzTrans extends TransStore { + public enum REQD_TYPE {future(1),force(2),move(4),ns(8); + public final int bit; + + REQD_TYPE(int bit) { + this.bit = bit; + } + }; + + public abstract AuthzTrans set(HttpServletRequest req); + + public abstract String user(); + + public abstract void setUser(TaggedPrincipal p); + + public abstract TaggedPrincipal getUserPrincipal(); + + public abstract String ip(); + + public abstract int port(); + + public abstract String meth(); + + public abstract String path(); + + public abstract String agent(); + + public abstract AuthzEnv env(); + + public abstract void setLur(Lur lur); + + public abstract boolean fish(Permission p); + + public abstract Organization org(); + + public abstract boolean requested(REQD_TYPE requested); + + public void requested(REQD_TYPE requested, boolean b); + + public abstract void logAuditTrail(LogTarget lt); + + public abstract Date now(); + +} \ No newline at end of file diff --git a/auth/auth-core/src/main/java/org/onap/aaf/auth/env/AuthzTransFilter.java b/auth/auth-core/src/main/java/org/onap/aaf/auth/env/AuthzTransFilter.java new file mode 100644 index 00000000..a25c5f31 --- /dev/null +++ b/auth/auth-core/src/main/java/org/onap/aaf/auth/env/AuthzTransFilter.java @@ -0,0 +1,181 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.env; + +import java.security.Principal; + +import javax.servlet.ServletRequest; +import javax.servlet.http.HttpServletRequest; + +import org.onap.aaf.auth.rserv.TransFilter; +import org.onap.aaf.cadi.CadiException; +import org.onap.aaf.cadi.Connector; +import org.onap.aaf.cadi.TrustChecker; +import org.onap.aaf.cadi.principal.TaggedPrincipal; +import org.onap.aaf.cadi.principal.TrustPrincipal; +import org.onap.aaf.misc.env.Env; +import org.onap.aaf.misc.env.LogTarget; +import org.onap.aaf.misc.env.Slot; +import org.onap.aaf.misc.env.TimeTaken; +import org.onap.aaf.misc.env.Trans.Metric; + +public class AuthzTransFilter extends TransFilter { + private AuthzEnv env; + public Metric serviceMetric; + public static Slot transIDslot,specialLogSlot; + + public static final String TRANS_ID_SLOT = "TRANS_ID_SLOT"; + public static final String SPECIAL_LOG_SLOT = "SPECIAL_LOG_SLOT"; + + public static final int BUCKETSIZE = 2; + + public AuthzTransFilter(AuthzEnv env, Connector con, TrustChecker tc, Object ... additionalTafLurs) throws CadiException { + super(env.access(),con, tc, additionalTafLurs); + this.env = env; + serviceMetric = new Metric(); + serviceMetric.buckets = new float[BUCKETSIZE]; + if(transIDslot==null) { + transIDslot = env.slot(TRANS_ID_SLOT); + } + if(specialLogSlot==null) { + specialLogSlot = env.slot(SPECIAL_LOG_SLOT); + } + } + + @Override + protected AuthzTrans newTrans() { + AuthzTrans at = env.newTrans(); + at.setLur(getLur()); + return at; + } + + @Override + protected TimeTaken start(AuthzTrans trans, ServletRequest request) { + trans.set((HttpServletRequest)request); + return trans.start("Trans " + //(context==null?"n/a":context.toString()) + + " IP: " + trans.ip() + + " Port: " + trans.port() + , Env.SUB); + } + + @Override + protected void authenticated(AuthzTrans trans, Principal p) { + trans.setUser((TaggedPrincipal)p); // We only work with TaggedPrincipals in Authz + } + + @Override + protected void tallyHo(AuthzTrans trans) { + Boolean b = trans.get(specialLogSlot, false); + LogTarget lt = b?trans.warn():trans.info(); + + if(lt.isLoggable()) { + // Transaction is done, now post full Audit Trail + StringBuilder sb = new StringBuilder("AuditTrail\n"); + // We'll grabAct sub-metrics for Remote Calls and JSON + // IMPORTANT!!! if you add more entries here, change "BUCKETSIZE"!!! + Metric m = trans.auditTrail(lt,1, sb, Env.REMOTE,Env.JSON); + + // Add current Metrics to total metrics + serviceMetric.total+= m.total; + for(int i=0;i=0) { + sb.append(content,start+6,content.length()-1); + } else { + sb.append(content); + } + sb.append('"'); + } + + trans.warn().log(sb); + } + } + +} diff --git a/auth/auth-core/src/main/java/org/onap/aaf/auth/env/AuthzTransImpl.java b/auth/auth-core/src/main/java/org/onap/aaf/auth/env/AuthzTransImpl.java new file mode 100644 index 00000000..2ca8dfd7 --- /dev/null +++ b/auth/auth-core/src/main/java/org/onap/aaf/auth/env/AuthzTransImpl.java @@ -0,0 +1,216 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.env; + +import java.util.Date; + +import javax.servlet.http.HttpServletRequest; + +import org.onap.aaf.auth.org.Organization; +import org.onap.aaf.auth.org.OrganizationFactory; +import org.onap.aaf.cadi.Lur; +import org.onap.aaf.cadi.Permission; +import org.onap.aaf.cadi.principal.TaggedPrincipal; +import org.onap.aaf.misc.env.LogTarget; +import org.onap.aaf.misc.env.impl.BasicTrans; + +public class AuthzTransImpl extends BasicTrans implements AuthzTrans { + private TaggedPrincipal user; + private String ip,agent,meth,path; + private int port; + private Lur lur; + private Organization org; + private int mask; + private Date now; + public AuthzTransImpl(AuthzEnv env) { + super(env); + ip="n/a"; + org=null; + mask=0; + } + + /** + * @see org.onap.aaf.auth.env.test.AuthTrans#set(javax.servlet.http.HttpServletRequest) + */ + @Override + public AuthzTrans set(HttpServletRequest req) { + user = (TaggedPrincipal)req.getUserPrincipal(); + ip = req.getRemoteAddr(); + port = req.getRemotePort(); + agent = req.getHeader("User-Agent"); + meth = req.getMethod(); + path = req.getPathInfo(); + + for(REQD_TYPE rt : REQD_TYPE.values()) { + requested(rt,req); + } + // Handle alternate "request" for "future" + String request = req.getParameter("request"); + if(request!=null) { + requested(REQD_TYPE.future,(request.length()==0 || "true".equalsIgnoreCase(request))); + } + + org=null; + return this; + } + + @Override + public void setUser(TaggedPrincipal p) { + user = p; + } + + /** + * @see org.onap.aaf.auth.env.test.AuthTrans#user() + */ + @Override + public String user() { + return user==null?"n/a":user.getName(); + } + + /** + * @see org.onap.aaf.auth.env.test.AuthTrans#getUserPrincipal() + */ + @Override + public TaggedPrincipal getUserPrincipal() { + return user; + } + + /** + * @see org.onap.aaf.auth.env.test.AuthTrans#ip() + */ + @Override + public String ip() { + return ip; + } + + /** + * @see org.onap.aaf.auth.env.test.AuthTrans#port() + */ + @Override + public int port() { + return port; + } + + + /* (non-Javadoc) + * @see org.onap.aaf.auth.env.test.AuthzTrans#meth() + */ + @Override + public String meth() { + return meth; + } + + /* (non-Javadoc) + * @see org.onap.aaf.auth.env.test.AuthzTrans#path() + */ + @Override + public String path() { + return path; + } + + /** + * @see org.onap.aaf.auth.env.test.AuthTrans#agent() + */ + @Override + public String agent() { + return agent; + } + + @Override + public AuthzEnv env() { + return (AuthzEnv)delegate; + } + + @Override + public boolean requested(REQD_TYPE requested) { + return (mask&requested.bit)==requested.bit; + } + + public void requested(REQD_TYPE requested, boolean b) { + if(b) { + mask|=requested.bit; + } else { + mask&=~requested.bit; + } + } + + private void requested(REQD_TYPE reqtype, HttpServletRequest req) { + String p = req.getParameter(reqtype.name()); + if(p!=null) { + requested(reqtype,p.length()==0 || "true".equalsIgnoreCase(p)); + } + } + + @Override + public void setLur(Lur lur) { + this.lur = lur; + } + + @Override + public boolean fish(Permission p) { + if(lur!=null) { + return lur.fish(user, p); + } + return false; + } + + /* (non-Javadoc) + * @see org.onap.aaf.auth.env.test.AuthzTrans#org() + */ + @Override + public Organization org() { + if(org==null) { + try { + if((org = OrganizationFactory.obtain(env(), user()))==null) { + org = Organization.NULL; + } + } catch (Exception e) { + + org = Organization.NULL; + } + } + return org; + } + + /* (non-Javadoc) + * @see org.onap.aaf.auth.env.test.AuthzTrans#logAuditTrailOnly(com.att.inno.env.LogTarget) + */ + @Override + public void logAuditTrail(LogTarget lt) { + if(lt.isLoggable()) { + StringBuilder sb = new StringBuilder(); + auditTrail(1, sb); + lt.log(sb); + } + } + + /* (non-Javadoc) + * @see org.onap.aaf.auth.env.test.AuthzTrans#now() + */ + @Override + public Date now() { + if(now==null) { + now = new Date(); + } + return now; + } +} diff --git a/auth/auth-core/src/main/java/org/onap/aaf/auth/env/AuthzTransOnlyFilter.java b/auth/auth-core/src/main/java/org/onap/aaf/auth/env/AuthzTransOnlyFilter.java new file mode 100644 index 00000000..2488cc7e --- /dev/null +++ b/auth/auth-core/src/main/java/org/onap/aaf/auth/env/AuthzTransOnlyFilter.java @@ -0,0 +1,86 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.env; + +import javax.servlet.ServletRequest; +import javax.servlet.http.HttpServletRequest; + +import org.onap.aaf.auth.rserv.TransOnlyFilter; +import org.onap.aaf.cadi.principal.TaggedPrincipal; +import org.onap.aaf.misc.env.Env; +import org.onap.aaf.misc.env.TimeTaken; +import org.onap.aaf.misc.env.Trans.Metric; + +public class AuthzTransOnlyFilter extends TransOnlyFilter { + private AuthzEnv env; + public Metric serviceMetric; + + public static final int BUCKETSIZE = 2; + + public AuthzTransOnlyFilter(AuthzEnv env) { + this.env = env; + serviceMetric = new Metric(); + serviceMetric.buckets = new float[BUCKETSIZE]; + } + + @Override + protected AuthzTrans newTrans() { + return env.newTrans(); + } + + @Override + protected TimeTaken start(AuthzTrans trans, ServletRequest request) { + trans.set((HttpServletRequest)request); + return trans.start("Trans " + //(context==null?"n/a":context.toString()) + + " IP: " + trans.ip() + + " Port: " + trans.port() + , Env.SUB); + } + + @Override + protected void authenticated(AuthzTrans trans, TaggedPrincipal p) { + trans.setUser(p); + } + + @Override + protected void tallyHo(AuthzTrans trans) { + // Transaction is done, now post + StringBuilder sb = new StringBuilder("AuditTrail\n"); + // We'll grab sub-metrics for Remote Calls and JSON + // IMPORTANT!!! if you add more entries here, change "BUCKETSIZE"!!! + Metric m = trans.auditTrail(1, sb, Env.REMOTE,Env.JSON); + // Add current Metrics to total metrics + serviceMetric.total+= m.total; + for(int i=0;i T get(Slot slot, T deflt) { + return null; + } + @Override + public T get(StaticSlot slot, T dflt) { + return null; + } + @Override + public Slot slot(String name) { + return null; + } + @Override + public AuthzEnv env() { + return null; + } + @Override + public String agent() { + return null; + } + + @Override + public void setLur(Lur lur) { + } + + @Override + public boolean fish(Permission p) { + return false; + } + + @Override + public Organization org() { + return Organization.NULL; + } + + @Override + public void logAuditTrail(LogTarget lt) { + } + + /* (non-Javadoc) + * @see org.onap.aaf.auth.env.test.AuthzTrans#requested(org.onap.aaf.auth.env.test.AuthzTrans.REQD_TYPE) + */ + @Override + public boolean requested(REQD_TYPE requested) { + return false; + } + + /* (non-Javadoc) + * @see org.onap.aaf.auth.env.test.AuthzTrans#requested(org.onap.aaf.auth.env.test.AuthzTrans.REQD_TYPE, boolean) + */ + @Override + public void requested(REQD_TYPE requested, boolean b) { + } + + @Override + public Date now() { + if(now==null) { + now = new Date(); + } + return now; + } +} + diff --git a/auth/auth-core/src/main/java/org/onap/aaf/auth/layer/DirectIntrospectImpl.java b/auth/auth-core/src/main/java/org/onap/aaf/auth/layer/DirectIntrospectImpl.java new file mode 100644 index 00000000..41f0e74a --- /dev/null +++ b/auth/auth-core/src/main/java/org/onap/aaf/auth/layer/DirectIntrospectImpl.java @@ -0,0 +1,26 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.layer; + +public class DirectIntrospectImpl { + +} diff --git a/auth/auth-core/src/main/java/org/onap/aaf/auth/layer/FacadeImpl.java b/auth/auth-core/src/main/java/org/onap/aaf/auth/layer/FacadeImpl.java new file mode 100644 index 00000000..81fc1e26 --- /dev/null +++ b/auth/auth-core/src/main/java/org/onap/aaf/auth/layer/FacadeImpl.java @@ -0,0 +1,42 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.layer; + +import javax.servlet.http.HttpServletResponse; + +import org.onap.aaf.misc.env.Data; +import org.onap.aaf.misc.env.Data.TYPE; + + + +public abstract class FacadeImpl { + protected static final String IN = "in"; + + protected void setContentType(HttpServletResponse response, TYPE type) { + response.setContentType(type==Data.TYPE.JSON?"application/json":"text.xml"); + } + + protected void setCacheControlOff(HttpServletResponse response) { + response.setHeader("Cache-Control", "no-store"); + response.setHeader("Pragma", "no-cache"); + } +} diff --git a/auth/auth-core/src/main/java/org/onap/aaf/auth/layer/Result.java b/auth/auth-core/src/main/java/org/onap/aaf/auth/layer/Result.java new file mode 100644 index 00000000..e61cf2e8 --- /dev/null +++ b/auth/auth-core/src/main/java/org/onap/aaf/auth/layer/Result.java @@ -0,0 +1,328 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.layer; + +import java.util.Collection; +import java.util.List; +import java.util.Set; + + +/** + * It would be nice if Java Enums were extensible, but they're not. + * + * @author Jonathan + * + */ +public class Result { + private static final String SUCCESS = "Success"; + public static final String[] EMPTY_VARS = new String[0]; + + public final static int OK=0, + ERR_Security = 1, + ERR_Denied = 2, + ERR_Policy = 3, + ERR_BadData = 4, + ERR_NotImplemented = 5, + ERR_NotFound = 6, + ERR_ConflictAlreadyExists = 7, + ERR_ActionNotCompleted = 8, + ERR_Backend = 9, + ERR_General = 20; + + public final RV value; + public final int status; + public final String details; + public final String[] variables; + + protected Result(RV value, int status, String details, String[] variables) { + this.value = value; + if(value==null) { + specialCondition|=EMPTY_LIST; + } + this.status = status; + this.details = details; + if(variables==null) { + this.variables = EMPTY_VARS; + } else { + this.variables=variables; + } + } + + /** + * Create a Result class with "OK" status and "Success" for details + * + * This is the easiest to use + * + * @param value + * @param status + * @return + */ + public static Result ok(R value) { + return new Result(value,OK,SUCCESS,null); + } + + /** + * Accept Arrays and mark as empty or not + * @param value + * @return + */ + public static Result ok(R value[]) { + return new Result(value,OK,SUCCESS,null).emptyList(value.length==0); + } + + /** + * Accept Sets and mark as empty or not + * @param value + * @return + */ + public static Result> ok(Set value) { + return new Result>(value,OK,SUCCESS,null).emptyList(value.size()==0); + } + + /** + * Accept Lists and mark as empty or not + * @param value + * @return + */ + public static Result> ok(List value) { + return new Result>(value,OK,SUCCESS,null).emptyList(value.size()==0); + } + + /** + * Accept Collections and mark as empty or not + * @param value + * @return + */ + public static Result> ok(Collection value) { + return new Result>(value,OK,SUCCESS,null).emptyList(value.size()==0); + } + + + /** + * Special Case for Void Type + * @return + */ + public static Result ok() { + return new Result(null,OK,SUCCESS,null); + } + + /** + * Create a Status (usually non OK, with a details statement + * @param value + * @param status + * @param details + * @return + */ +// public static Result err(int status, String details) { +// return new Result(null,status,details,null); +// } + + /** + * Create a Status (usually non OK, with a details statement and variables supported + * @param status + * @param details + * @param variables + * @return + */ + public static Result err(int status, String details, String ... variables) { + return new Result(null,status,details,variables); + } + + /** + * Create Error from status and Details of previous Result (and not data) + * @param pdr + * @return + */ + public static Result err(Result pdr) { + return new Result(null,pdr.status,pdr.details,pdr.variables); + } + + /** + * Create General Error from Exception + * @param e + * @return + */ + public static Result err(Exception e) { + return new Result(null,ERR_General,e.getMessage(),EMPTY_VARS); + } + + /** + * Create a Status (usually non OK, with a details statement + * @param value + * @param status + * @param details + * @return + */ + public static Result create(R value, int status, String details, String ... vars) { + return new Result(value,status,details,vars); + } + + /** + * Create a Status from a previous status' result/details + * @param value + * @param status + * @param details + * @return + */ + public static Result create(R value, Result result) { + return new Result(value,result.status,result.details,result.variables); + } + + private static final int PARTIAL_CONTENT = 0x001; + private static final int EMPTY_LIST = 0x002; + + /** + * AAF Specific problems, etc + * + * @author Jonathan + * + */ + + /** + * specialCondition is a bit field to enable multiple conditions, e.g. PARTIAL_CONTENT + */ + private int specialCondition = 0; + + + /** + * Is result set only partial results, i.e. the DAO clipped the real result set to a smaller number. + * @return true iff result returned PARTIAL_CONTENT + */ + public boolean partialContent() { + return (specialCondition & PARTIAL_CONTENT) == PARTIAL_CONTENT; + } + + /** + * Set fact that result set only returned partial results, i.e. the DAO clipped the real result set to a smaller number. + * @param hasPartialContent set true iff result returned PARTIAL_CONTENT + * @return this Result object, so you can chain calls, in builder style + */ + public Result partialContent(boolean hasPartialContent) { + if (hasPartialContent) { + specialCondition |= PARTIAL_CONTENT; + } else { + specialCondition &= (~PARTIAL_CONTENT); + } + return this; + } + + /** + * When Result is a List, you can check here to see if it's empty instead of looping + * + * @return + */ + public boolean isEmpty() { + return (specialCondition & EMPTY_LIST) == EMPTY_LIST; + } + + /** + * A common occurrence is that data comes back, but list is empty. If set, you can skip looking + * at list at the outset. + * + * @param emptyList + * @return + */ + public Result emptyList(boolean emptyList) { + if (emptyList) { + specialCondition |= EMPTY_LIST; + } else { + specialCondition &= (~EMPTY_LIST); + } + return this; + } + + + /** + * Convenience function. Checks OK, and also if List is not Empty + * Not valid if Data is not a List + * @return + */ + public boolean isOK() { + return status == OK; + } + + /** + * Convenience function. Checks OK, and also if List is not Empty + * Not valid if Data is not a List + * @return + */ + public boolean notOK() { + return status != OK; + } + + /** + * Convenience function. Checks OK, and also if List is not Empty + * Not valid if Data is not a List + * @return + */ + public boolean isOKhasData() { + return status == OK && (specialCondition & EMPTY_LIST) != EMPTY_LIST; + } + + + /** + * Convenience function. Checks OK, and also if List is not Empty + * Not valid if Data is not a List + * @return + */ + public boolean notOKorIsEmpty() { + return status != OK || (specialCondition & EMPTY_LIST) == EMPTY_LIST; + } + + @Override + public String toString() { + if(status==0) { + return details; + } else { + StringBuilder sb = new StringBuilder(); + sb.append(status); + sb.append(':'); + sb.append(String.format(details,((Object[])variables))); + if(isEmpty()) { + sb.append("{empty}"); + } + if(value!=null) { + sb.append('-'); + sb.append(value.toString()); + } + return sb.toString(); + } + } + + public String errorString() { + StringBuilder sb = new StringBuilder(); + switch(status) { + case 1: sb.append("Security"); break; + case 2: sb.append("Denied"); break; + case 3: sb.append("Policy"); break; + case 4: sb.append("BadData"); break; + case 5: sb.append("NotImplemented"); break; + case 6: sb.append("NotFound"); break; + case 7: sb.append("AlreadyExists"); break; + case 8: sb.append("ActionNotComplete"); break; + default: sb.append("Error"); + } + sb.append(" - "); + sb.append(String.format(details, (Object[])variables)); + return sb.toString(); + } +} diff --git a/auth/auth-core/src/main/java/org/onap/aaf/auth/local/AbsData.java b/auth/auth-core/src/main/java/org/onap/aaf/auth/local/AbsData.java new file mode 100644 index 00000000..40e0b22c --- /dev/null +++ b/auth/auth-core/src/main/java/org/onap/aaf/auth/local/AbsData.java @@ -0,0 +1,206 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.local; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.RandomAccessFile; +import java.util.Iterator; + +import org.onap.aaf.auth.env.AuthzTrans; +import org.onap.aaf.auth.local.DataFile.Token; +import org.onap.aaf.auth.local.DataFile.Token.Field; +import org.onap.aaf.misc.env.Env; +import org.onap.aaf.misc.env.TimeTaken; + +public abstract class AbsData implements Iterable { + protected DataFile data; + protected TextIndex ti; + private File dataf,idxf,lockf; + private String name; + private char delim; + private int maxLineSize; + private int fieldOffset; + private int skipLines; + + public AbsData(File dataf,char sepChar, int maxLineSize, int fieldOffset) { + File dir = dataf.getParentFile(); + int dot = dataf.getName().lastIndexOf('.'); + name = dataf.getName().substring(0,dot); + + this.dataf=dataf; + this.delim = sepChar; + this.maxLineSize = maxLineSize; + this.fieldOffset = fieldOffset; + idxf = new File(dir,name.concat(".idx")); + lockf = new File(dir,name.concat(".lock")); + + + data = new DataFile(dataf,"r"); + ti = new TextIndex(idxf); + skipLines=0; + } + + public void skipLines(int lines) { + skipLines=lines; + } + + public String name() { + return name; + } + + public void open(AuthzTrans trans, long timeout) throws IOException { + TimeTaken tt = trans.start("Open Data File", Env.SUB); + boolean opened = false, first = true; + try { + if(!dataf.exists()) { + throw new FileNotFoundException("Data File Missing:" + dataf.getCanonicalPath()); + } + long begin = System.currentTimeMillis(); + long end = begin+timeout; + boolean exists; + while((exists=lockf.exists()) && beginidxf.lastModified()) { + trans.warn().log(idxf.getAbsolutePath(),"is missing, empty or out of date, creating"); + RandomAccessFile raf = new RandomAccessFile(lockf, "rw"); + try { + ti.create(trans, data, maxLineSize, delim, fieldOffset, skipLines); + if(!idxf.exists() || (idxf.length()==0 && dataf.length()!=0)) { + throw new IOException("Data Index File did not create correctly"); + } + } finally { + raf.close(); + lockf.delete(); + } + } + } + + public void close(AuthzTrans trans) throws IOException { + ti.close(); + data.close(); + } + + public class Reuse { + public Token tokenData; + private Field fieldData; + + private Reuse(int size,char delim) { + tokenData = data.new Token(size); + fieldData = tokenData.new Field(delim); + } + + public void reset() { + getFieldData().reset(); + } + + public void pos(int rec) { + getFieldData().reset(); + tokenData.pos(rec); + } + + public String next() { + return getFieldData().next(); + } + + public String at(int field) { + return getFieldData().at(field); + } + + public String atToEnd(int field) { + return getFieldData().atToEnd(field); + } + + public Field getFieldData() { + return fieldData; + } + } + + public Reuse reuse() { + return new Reuse(maxLineSize,delim); + } + + public Iter iterator() { + return new Iter(); + } + + public class Iter implements Iterator { + private Reuse reuse; + private org.onap.aaf.auth.local.TextIndex.Iter tii; + + public Iter() { + reuse = reuse(); + tii = ti.new Iter(); + } + + @Override + public boolean hasNext() { + return tii.hasNext(); + } + + @Override + public String next() { + reuse.reset(); + int rec = tii.next(); + reuse.pos(rec); + return reuse.at(0); + } + + @Override + public void remove() { + // read only + } + } +} diff --git a/auth/auth-core/src/main/java/org/onap/aaf/auth/local/DataFile.java b/auth/auth-core/src/main/java/org/onap/aaf/auth/local/DataFile.java new file mode 100644 index 00000000..bb9fb1fd --- /dev/null +++ b/auth/auth-core/src/main/java/org/onap/aaf/auth/local/DataFile.java @@ -0,0 +1,190 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.local; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.RandomAccessFile; +import java.nio.ByteBuffer; +import java.nio.IntBuffer; +import java.nio.MappedByteBuffer; +import java.nio.channels.FileChannel; +import java.nio.channels.FileChannel.MapMode; + +public class DataFile { + private RandomAccessFile rafile; + private FileChannel channel; + public MappedByteBuffer mapBuff; + private final File file; + private final String access; + + public DataFile(File file, String access) { + this.file = file; + this.access = access; + } + public void open() throws IOException { + if(!file.exists()) throw new FileNotFoundException(); + rafile = new RandomAccessFile(file,access); + channel = rafile.getChannel(); + mapBuff = channel.map("r".equals(access)?MapMode.READ_ONLY:MapMode.READ_WRITE,0,channel.size()); + } + public boolean isOpened() { + return mapBuff!=null; + } + public void close() throws IOException { + if(channel!=null){ + channel.close(); + } + if(rafile!=null) { + rafile.close(); + } + mapBuff = null; + } + + public long size() throws IOException { + return channel==null?0:channel.size(); + } + + private synchronized int load(Token t) { + int len = Math.min(mapBuff.limit()-t.next,t.buff.length); + if(len>0) { + mapBuff.position(t.next); + mapBuff.get(t.buff,0,len); + } + return len<0?0:len; + } + + public class Token { + private byte[] buff; + int pos, next, end; + + public Token(int size) { + buff = new byte[size]; + pos = next = end = 0; + } + + public boolean pos(int to) { + pos = next = to; + return (end=load(this))>0; + } + + public boolean nextLine() { + end = load(this); + pos = next; + for(int i=0;i=end)return null; + int start = idx; + byte c=0; + int endStr = -1; + while(idx=end)?1:0))); + } + + } + + public int pos() { + return pos; + } + } + + public File file() { + return file; + } + +} diff --git a/auth/auth-core/src/main/java/org/onap/aaf/auth/local/TextIndex.java b/auth/auth-core/src/main/java/org/onap/aaf/auth/local/TextIndex.java new file mode 100644 index 00000000..5169cf88 --- /dev/null +++ b/auth/auth-core/src/main/java/org/onap/aaf/auth/local/TextIndex.java @@ -0,0 +1,256 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.local; + +import java.io.File; +import java.io.IOException; +import java.io.RandomAccessFile; +import java.nio.ByteBuffer; +import java.nio.IntBuffer; +import java.nio.channels.FileChannel; +import java.util.ArrayList; +import java.util.Collections; +import java.util.LinkedList; +import java.util.List; + +import org.onap.aaf.auth.local.DataFile.Token; +import org.onap.aaf.auth.local.DataFile.Token.Field; +import org.onap.aaf.misc.env.Env; +import org.onap.aaf.misc.env.TimeTaken; +import org.onap.aaf.misc.env.Trans; + +public class TextIndex { + private static final int REC_SIZE=8; + + private File file; + private DataFile dataFile=null; + + public TextIndex(File theFile) { + file = theFile; + } + + public void open() throws IOException { + dataFile = new DataFile(file,"r"); + dataFile.open(); + } + + public void close() throws IOException { + if(dataFile!=null) { + dataFile.close(); + dataFile=null; + } + } + + public int find(Object key, AbsData.Reuse reuse, int offset) throws IOException { + return find(key,reuse.tokenData,reuse.getFieldData(),offset); + } + + public int find(Object key, DataFile.Token dtok, Field df, int offset) throws IOException { + if(dataFile==null) { + throw new IOException("File not opened"); + } + long hash = hashToLong(key.hashCode()); + int min=0, max = (int)(dataFile.size()/REC_SIZE); + Token ttok = dataFile.new Token(REC_SIZE); + IntBuffer tib = ttok.getIntBuffer(); + long lhash; + int curr; + while((max-min)>100) { + ttok.pos((curr=(min+(max-min)/2))*REC_SIZE); + tib.rewind(); + lhash = hashToLong(tib.get()); + if(lhashhash) { + max=curr-1; + } else { + min=curr-40; + max=curr+40; + break; + } + } + + List entries = new ArrayList(); + for(int i=min;i<=max;++i) { + ttok.pos(i*REC_SIZE); + tib.rewind(); + lhash = hashToLong(tib.get()); + if(lhash==hash) { + entries.add(tib.get()); + } else if(lhash>hash) { + break; + } + } + + for(Integer i : entries) { + dtok.pos(i); + if(df.at(offset).equals(key)) { + return i; + } + } + return -1; + } + + + /* + * Have to change Bytes into a Long, to avoid the inevitable signs in the Hash + */ + private static long hashToLong(int hash) { + long rv; + if(hash<0) { + rv = 0xFFFFFFFFL & hash; + } else { + rv = hash; + } + return rv; + } + + public void create(final Trans trans,final DataFile data, int maxLine, char delim, int fieldOffset, int skipLines) throws IOException { + RandomAccessFile raf; + FileChannel fos; + + List list = new LinkedList(); // Some hashcodes will double... DO NOT make a set + TimeTaken tt2 = trans.start("Open Files", Env.SUB); + try { + raf = new RandomAccessFile(file,"rw"); + raf.setLength(0L); + fos = raf.getChannel(); + } finally { + tt2.done(); + } + + try { + + Token t = data.new Token(maxLine); + Field f = t.new Field(delim); + + int count = 0; + if(skipLines>0) { + trans.info().log("Skipping",skipLines,"line"+(skipLines==1?" in":"s in"),data.file().getName()); + } + for(int i=0;i { + public int hash, pos; + public Idx(Object obj, int pos) { + hash = obj.hashCode(); + this.pos = pos; + } + + @Override + public int compareTo(Idx ib) { + long a = hashToLong(hash); + long b = hashToLong(ib.hash); + return a>b?1:a 1, remove User from Owner + // if # of Owners = 1, changeOwner to X Remove Owner???? + boolean hasPermission(String user, String ns, String type, String instance, String action); + boolean inRole(String name); + + public String namespace() throws Exception; + public String id(); +} diff --git a/auth/auth-core/src/main/java/org/onap/aaf/auth/org/Organization.java b/auth/auth-core/src/main/java/org/onap/aaf/auth/org/Organization.java new file mode 100644 index 00000000..6d7a3586 --- /dev/null +++ b/auth/auth-core/src/main/java/org/onap/aaf/auth/org/Organization.java @@ -0,0 +1,515 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.org; + +import java.util.ArrayList; +import java.util.Date; +import java.util.GregorianCalendar; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import org.onap.aaf.auth.env.AuthzTrans; + +/** + * Organization + * + * There is Organizational specific information required which we have extracted to a plugin + * + * It supports using Company Specific User Directory lookups, as well as supporting an + * Approval/Validation Process to simplify control of Roles and Permissions for large organizations + * in lieu of direct manipulation by a set of Admins. + * + * @author Jonathan + * + */ +public interface Organization { + public static final String N_A = "n/a"; + + public interface Identity { + public String id(); + public String fullID() throws OrganizationException; // Fully Qualified ID (includes Domain of Organization) + public String type(); // Must be one of "IdentityTypes", see below + public Identity responsibleTo() throws OrganizationException; // Chain of Command, or Application ID Sponsor + public List delegate(); // Someone who has authority to act on behalf of Identity + public String email(); + public String fullName(); + public String firstName(); + /** + * If Responsible entity, then String returned is "null" meaning "no Objection". + * If String exists, it is the Policy objection text setup by the entity. + * @return + */ + public String mayOwn(); // Is id passed belong to a person suitable to be Responsible for content Management + public boolean isFound(); // Is Identity found in Identity stores + public boolean isPerson(); // Whether a Person or a Machine (App) + public Organization org(); // Organization of Identity + + } + + + /** + * Name of Organization, suitable for Logging + * @return + */ + public String getName(); + + /** + * Realm, for use in distinguishing IDs from different systems/Companies + * @return + */ + public String getRealm(); + + String getDomain(); + + /** + * Get Identity information based on userID + * + * @param id + * @return + */ + public Identity getIdentity(AuthzTrans trans, String id) throws OrganizationException; + + + /** + * Does the ID pass Organization Standards + * + * Return a Blank (empty) String if empty, otherwise, return a "\n" separated list of + * reasons why it fails + * + * @param id + * @return + */ + public String isValidID(AuthzTrans trans, String id); + + /** + * Return a Blank (empty) String if empty, otherwise, return a "\n" separated list of + * reasons why it fails + * + * Identity is passed in to allow policies regarding passwords that are the same as user ID + * + * any entries for "prev" imply a reset + * + * @param id + * @param password + * @return + */ + public String isValidPassword(final AuthzTrans trans, final String id, final String password, final String ... prev); + + /** + * Return a list of Strings denoting Organization Password Rules, suitable for posting on a WebPage with

+ */ + public String[] getPasswordRules(); + + /** + * + * @param id + * @return + */ + public boolean isValidCred(final AuthzTrans trans, final String id); + + /** + * If response is Null, then it is valid. Otherwise, the Organization specific reason is returned. + * + * @param trans + * @param policy + * @param executor + * @param vars + * @return + * @throws OrganizationException + */ + public String validate(AuthzTrans trans, Policy policy, Executor executor, String ... vars) throws OrganizationException; + + /** + * Does your Company distinguish essential permission structures by kind of Identity? + * i.e. Employee, Contractor, Vendor + * @return + */ + public Set getIdentityTypes(); + + public enum Notify { + Approval(1), + PasswordExpiration(2), + RoleExpiration(3); + + final int id; + Notify(int id) {this.id = id;} + public int getValue() {return id;} + public static Notify from(int type) { + for(Notify t : Notify.values()) { + if(t.id==type) { + return t; + } + } + return null; + } + } + + public enum Response{ + OK, + ERR_NotImplemented, + ERR_UserNotExist, + ERR_NotificationFailure, + }; + + public enum Expiration { + Password, + TempPassword, + Future, + UserInRole, + UserDelegate, + ExtendPassword + } + + public enum Policy { + CHANGE_JOB, + LEFT_COMPANY, + CREATE_MECHID, + CREATE_MECHID_BY_PERM_ONLY, + OWNS_MECHID, + AS_RESPONSIBLE, + MAY_EXTEND_CRED_EXPIRES, + MAY_APPLY_DEFAULT_REALM + } + + /** + * Notify a User of Action or Info + * + * @param type + * @param url + * @param users (separated by commas) + * @param ccs (separated by commas) + * @param summary + */ + + public Response notify(AuthzTrans trans, Notify type, String url, String ids[], String ccs[], String summary, Boolean urgent); + + /** + * (more) generic way to send an email + * + * @param toList + * @param ccList + * @param subject + * @param body + * @param urgent + */ + + public int sendEmail(AuthzTrans trans, List toList, List ccList, String subject, String body, Boolean urgent) throws OrganizationException; + + /** + * whenToValidate + * + * Authz support services will ask the Organization Object at startup when it should + * kickoff Validation processes given particular types. + * + * This allows the Organization to express Policy + * + * Turn off Validation behavior by returning "null" + * + */ + public Date whenToValidate(Notify type, Date lastValidated); + + + /** + * Expiration + * + * Given a Calendar item of Start (or now), set the Expiration Date based on the Policy + * based on type. + * + * For instance, "Passwords expire in 3 months" + * + * The Extra Parameter is used by certain Orgs. + * + * For Password, the extra is UserID, so it can check the User Type + * + * @param gc + * @param exp + * @return + */ + public GregorianCalendar expiration(GregorianCalendar gc, Expiration exp, String ... extra); + + /** + * Get Email Warning timing policies + * @return + */ + public EmailWarnings emailWarningPolicy(); + + /** + * + * @param trans + * @param user + * @return + */ + public List getApprovers(AuthzTrans trans, String user) throws OrganizationException ; + + /* + * + * @param user + * @param type + * @param users + * @return + public Response notifyRequest(AuthzTrans trans, String user, Approval type, List approvers); + */ + + /** + * + * @return + */ + public String getApproverType(); + + /* + * startOfDay - define for company what hour of day business starts (specifically for password and other expiration which + * were set by Date only.) + * + * @return + */ + public int startOfDay(); + + /** + * implement this method to support any IDs that can have multiple entries in the cred table + * NOTE: the combination of ID/expiration date/(encryption type when implemented) must be unique. + * Since expiration date is based on startOfDay for your company, you cannot create many + * creds for the same ID in the same day. + * @param id + * @return + */ + public boolean canHaveMultipleCreds(String id); + + boolean isTestEnv(); + + public void setTestMode(boolean dryRun); + + public static final Organization NULL = new Organization() + { + private final GregorianCalendar gc = new GregorianCalendar(1900, 1, 1); + private final List nullList = new ArrayList(); + private final Set nullStringSet = new HashSet(); + private String[] nullStringArray = new String[0]; + private final Identity nullIdentity = new Identity() { + List nullUser = new ArrayList(); + @Override + public String type() { + return N_A; + } + + @Override + public String mayOwn() { + return N_A; // negative case + } + + @Override + public boolean isFound() { + return false; + } + + @Override + public String id() { + return N_A; + } + + @Override + public String fullID() { + return N_A; + } + + @Override + public String email() { + return N_A; + } + + @Override + public List delegate() { + return nullUser; + } + @Override + public String fullName() { + return N_A; + } + @Override + public Organization org() { + return NULL; + } + @Override + public String firstName() { + return N_A; + } + @Override + public boolean isPerson() { + return false; + } + + @Override + public Identity responsibleTo() { + return null; + } + }; + @Override + public String getName() { + return N_A; + } + + @Override + public String getRealm() { + return N_A; + } + + @Override + public String getDomain() { + return N_A; + } + + @Override + public Identity getIdentity(AuthzTrans trans, String id) { + return nullIdentity; + } + + @Override + public String isValidID(final AuthzTrans trans, String id) { + return N_A; + } + + @Override + public String isValidPassword(final AuthzTrans trans, final String user, final String password, final String... prev) { + return N_A; + } + + @Override + public Set getIdentityTypes() { + return nullStringSet; + } + + @Override + public Response notify(AuthzTrans trans, Notify type, String url, + String[] users, String[] ccs, String summary, Boolean urgent) { + return Response.ERR_NotImplemented; + } + + @Override + public int sendEmail(AuthzTrans trans, List toList, List ccList, + String subject, String body, Boolean urgent) throws OrganizationException { + return 0; + } + + @Override + public Date whenToValidate(Notify type, Date lastValidated) { + return gc.getTime(); + } + + @Override + public GregorianCalendar expiration(GregorianCalendar gc, + Expiration exp, String... extra) { + return gc; + } + + @Override + public List getApprovers(AuthzTrans trans, String user) + throws OrganizationException { + return nullList; + } + + @Override + public String getApproverType() { + return ""; + } + + @Override + public int startOfDay() { + return 0; + } + + @Override + public boolean canHaveMultipleCreds(String id) { + return false; + } + + @Override + public boolean isValidCred(final AuthzTrans trans, final String id) { + return false; + } + + @Override + public String validate(AuthzTrans trans, Policy policy, Executor executor, String ... vars) + throws OrganizationException { + return "Null Organization rejects all Policies"; + } + + @Override + public boolean isTestEnv() { + return false; + } + + @Override + public void setTestMode(boolean dryRun) { + } + + @Override + public EmailWarnings emailWarningPolicy() { + return new EmailWarnings() { + + @Override + public long credEmailInterval() + { + return 604800000L; // 7 days in millis 1000 * 86400 * 7 + } + + @Override + public long roleEmailInterval() + { + return 604800000L; // 7 days in millis 1000 * 86400 * 7 + } + + @Override + public long apprEmailInterval() { + return 259200000L; // 3 days in millis 1000 * 86400 * 3 + } + + @Override + public long credExpirationWarning() + { + return( 2592000000L ); // One month, in milliseconds 1000 * 86400 * 30 in milliseconds + } + + @Override + public long roleExpirationWarning() + { + return( 2592000000L ); // One month, in milliseconds 1000 * 86400 * 30 in milliseconds + } + + @Override + public long emailUrgentWarning() + { + return( 1209600000L ); // Two weeks, in milliseconds 1000 * 86400 * 14 in milliseconds + } + + }; + } + + @Override + public String[] getPasswordRules() { + return nullStringArray; + } + + }; + +} + + diff --git a/auth/auth-core/src/main/java/org/onap/aaf/auth/org/OrganizationException.java b/auth/auth-core/src/main/java/org/onap/aaf/auth/org/OrganizationException.java new file mode 100644 index 00000000..ed1d398b --- /dev/null +++ b/auth/auth-core/src/main/java/org/onap/aaf/auth/org/OrganizationException.java @@ -0,0 +1,52 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.org; + +public class OrganizationException extends Exception { + + /** + * + */ + private static final long serialVersionUID = 1L; + + public OrganizationException() { + super(); + } + + public OrganizationException(String message) { + super(message); + } + + public OrganizationException(Throwable cause) { + super(cause); + } + + public OrganizationException(String message, Throwable cause) { + super(message, cause); + } + + public OrganizationException(String message, Throwable cause, boolean enableSuppression, + boolean writableStackTrace) { + super(message, cause, enableSuppression, writableStackTrace); + } + +} diff --git a/auth/auth-core/src/main/java/org/onap/aaf/auth/org/OrganizationFactory.java b/auth/auth-core/src/main/java/org/onap/aaf/auth/org/OrganizationFactory.java new file mode 100644 index 00000000..36efb5dc --- /dev/null +++ b/auth/auth-core/src/main/java/org/onap/aaf/auth/org/OrganizationFactory.java @@ -0,0 +1,125 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.org; + +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; +import java.util.Map; +import java.util.Map.Entry; +import java.util.concurrent.ConcurrentHashMap; + +import org.onap.aaf.auth.env.AuthzTrans; +import org.onap.aaf.cadi.util.FQI; +import org.onap.aaf.misc.env.Env; +import org.onap.aaf.misc.env.impl.BasicEnv; + +/** + * Organization Plugin Mechanism + * + * Define a NameSpace for the company (i.e. com.att), and put in Properties as + * "Organization.[your NS" and assign the supporting Class. + * + * Example: + * Organization.com.att=org.onap.aaf.auth.org.test.att.ATT + * + * @author Pavani, Jonathan + * + */ +public class OrganizationFactory { + private static final String ORGANIZATION_DOT = "Organization."; + private static Organization defaultOrg = null; + private static Map orgs = new ConcurrentHashMap(); + public static Organization init(BasicEnv env) throws OrganizationException { + int idx = ORGANIZATION_DOT.length(); + Organization org,firstOrg = null; + + for(Entry es : env.getProperties().entrySet()) { + String key = es.getKey().toString(); + if(key.startsWith(ORGANIZATION_DOT)) { + org = obtain(env,key.substring(idx)); + if(firstOrg==null) { + firstOrg = org; + } + } + } + if(defaultOrg == null) { + defaultOrg = firstOrg; + } + return defaultOrg; + } + public static Organization obtain(Env env,final String theNS) throws OrganizationException { + String orgNS; + if(theNS.indexOf('@')>=0) { + orgNS=FQI.reverseDomain(theNS); + } else { + orgNS=theNS; + } + Organization org = orgs.get(orgNS); + if(org == null) { + String orgClass = env.getProperty(ORGANIZATION_DOT+orgNS); + if(orgClass == null) { + env.warn().log("There is no Organization." + orgNS + " property"); + } else { + for(Organization o : orgs.values()) { + if(orgClass.equals(o.getClass().getName())) { + org = o; + } + } + if(org==null) { + try { + @SuppressWarnings("unchecked") + Class cls = (Class) Class.forName(orgClass); + Constructor cnst = cls.getConstructor(Env.class,String.class); + org = cnst.newInstance(env,orgNS); + } catch (ClassNotFoundException | NoSuchMethodException | SecurityException | + InstantiationException | IllegalAccessException | IllegalArgumentException | + InvocationTargetException e) { + env.error().log(e, "Error on Organization Construction"); + throw new OrganizationException(e); + } + } + orgs.put(orgNS, org); + if("true".equalsIgnoreCase(env.getProperty(orgNS+".default"))) { + defaultOrg = org; + } + + } + if(org==null) { + if(defaultOrg!=null) { + org=defaultOrg; + orgs.put(orgNS, org); + } + } + } + + return org; + } + + public static Organization get(AuthzTrans trans) throws OrganizationException { + String domain = FQI.reverseDomain(trans.user()); + Organization org = orgs.get(domain); + if(org==null) { + org = defaultOrg; // can be null, btw, unless set. + } + return org; + } +} diff --git a/auth/auth-core/src/main/java/org/onap/aaf/auth/rserv/Acceptor.java b/auth/auth-core/src/main/java/org/onap/aaf/auth/rserv/Acceptor.java new file mode 100644 index 00000000..1953694b --- /dev/null +++ b/auth/auth-core/src/main/java/org/onap/aaf/auth/rserv/Acceptor.java @@ -0,0 +1,169 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.rserv; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import org.onap.aaf.misc.env.Trans; + +/** + * Find Acceptable Paths and place them where TypeCode can evaluate. + * + * If there are more than one, TypeCode will choose based on "q" value + * @author Jonathan + * + * @param + */ +class Acceptor { + private List, List>>>> types; + List, List>>>> acceptable; + + public Acceptor(List, List>>>> types) { + this.types = types; + acceptable = new ArrayList, List>>>>(); + } + + private boolean eval(HttpCode code, String str, List props) { +// int plus = str.indexOf('+'); +// if(plus<0) { + boolean ok = false; + boolean any = false; + for(Pair, List>>> type : types) { + ok = true; + if(type.x.equals(str)) { + for(Iterator iter = props.iterator();ok && iter.hasNext();) { + ok = props(type,iter.next(),iter.next()); + } + if(ok) { + any = true; + acceptable.add(type); + } + } + } +// } else { // Handle Accepts with "+" as in application/xaml+xml +// int prev = str.indexOf('/')+1; +// String first = str.substring(0,prev); +// String nstr; +// while(prev!=0) { +// nstr = first + (plus<0?str.substring(prev):str.substring(prev,plus)); +// +// for(Pair, List>>> type : types) { +// if(type.x.equals(nstr)) { +// acceptable.add(type); +// return type; +// } +// } +// prev = plus+1; +// plus=str.indexOf('+', prev); +// }; +// } + return any; + } + + /** + * Evaluate Properties + * @param type + * @param tag + * @param value + * @return + */ + private boolean props(Pair, List>>> type, String tag, String value) { + boolean rv = false; + if(type.y!=null) { + for(Pair prop : type.y.y){ + if(tag.equals(prop.x)) { + if(tag.equals("charset")) { + return prop.x==null?false:prop.y.equals(value.toLowerCase()); // return True if Matched + } else if(tag.equals("version")) { + return prop.y.equals(new Version(value)); // Note: Version Class knows Minor Version encoding + } else if(tag.equals(Content.Q)) { // replace Q value + try { + type.y.y.get(0).y=Float.parseFloat(value); + } catch (NumberFormatException e) { + rv=false; // need to do something to make Sonar happy. But nothing to do. + } + return true; + } else { + return value.equals(prop.y); + } + } + } + } + return rv; + } + + /** + * parse + * + * Note: I'm processing by index to avoid lots of memory creation, which speeds things + * up for this time critical section of code. + * @param code + * @param cntnt + * @return + */ + protected boolean parse(HttpCode code, String cntnt) { + byte bytes[] = cntnt.getBytes(); + + int cis,cie=-1,cend; + int sis,sie,send; + String name; + ArrayList props = new ArrayList(); + do { + // Clear these in case more than one Semi + props.clear(); // on loop, do not want mixed properties + name=null; + + cis = cie+1; // find comma start + while(ciscis && Character.isSpaceChar(bytes[cend-1]))--cend; + // Start SEMIS + sie=cis-1; + do { + sis = sie+1; // semi start is one after previous end + while(siscend || sie<0?cend:sie; // if the Semicolon is after the comma, or non-existent, use comma end, else keep + while(send>sis && Character.isSpaceChar(bytes[send-1]))--send; + if(name==null) { // first entry in Comma set is the name, not a property + name = new String(bytes,sis,send-sis); + } else { // We've looped past the first Semi, now process as properties + // If there are additional elements (more entities within Semi Colons) + // apply Properties + int eq = cntnt.indexOf('=',sis); + if(eq>sis && eq=cis); // End SEMI processing + // Now evaluate Comma set and return if true + if(eval(code,name,props))return true; // else loop again to check next comma + } while(cie>=0); // loop to next comma + return false; // didn't get even one match + } + +} \ No newline at end of file diff --git a/auth/auth-core/src/main/java/org/onap/aaf/auth/rserv/CachingFileAccess.java b/auth/auth-core/src/main/java/org/onap/aaf/auth/rserv/CachingFileAccess.java new file mode 100644 index 00000000..7bb276a2 --- /dev/null +++ b/auth/auth-core/src/main/java/org/onap/aaf/auth/rserv/CachingFileAccess.java @@ -0,0 +1,564 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.rserv; + + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.FileReader; +import java.io.IOException; +import java.io.OutputStream; +import java.io.OutputStreamWriter; +import java.io.Writer; +import java.nio.ByteBuffer; +import java.nio.channels.FileChannel; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.Comparator; +import java.util.Date; +import java.util.HashSet; +import java.util.Map; +import java.util.Map.Entry; +import java.util.NavigableMap; +import java.util.Set; +import java.util.Timer; +import java.util.TimerTask; +import java.util.TreeMap; +import java.util.concurrent.ConcurrentSkipListMap; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.onap.aaf.misc.env.Env; +import org.onap.aaf.misc.env.EnvJAXB; +import org.onap.aaf.misc.env.LogTarget; +import org.onap.aaf.misc.env.Store; +import org.onap.aaf.misc.env.TimeTaken; +import org.onap.aaf.misc.env.Trans; +/* + * CachingFileAccess + * + * Author: Jonathan Gathman, Gathsys 2010 + * + */ +public class CachingFileAccess extends HttpCode { + public static void setEnv(Store store, String[] args) { + for(int i=0;i typeMap; + private final NavigableMap content; + private final Set attachOnly; + public final static String CFA_WEB_PATH = "aaf_cfa_web_path"; + // when to re-validate from file + // Re validating means comparing the Timestamp on the disk, and seeing it has changed. Cache is not marked + // dirty unless file has changed, but it still makes File IO, which for some kinds of cached data, i.e. + // deployed GUI elements is unnecessary, and wastes time. + // This parameter exists to cover the cases where data can be more volatile, so the user can choose how often the + // File IO will be accessed, based on probability of change. "0", of course, means, check every time. + private final static String CFA_CACHE_CHECK_INTERVAL = "aaf_cfa_cache_check_interval"; + private final static String CFA_MAX_SIZE = "aaf_cfa_max_size"; // Cache size limit + private final static String CFA_CLEAR_COMMAND = "aaf_cfa_clear_command"; + + // Note: can be null without a problem, but included + // to tie in with existing Logging. + public LogTarget logT = null; + public long checkInterval; // = 600000L; // only check if not hit in 10 mins by default + public int maxItemSize; // = 512000; // max file 500k + private Timer timer; + private String web_path; + // A command key is set in the Properties, preferably changed on deployment. + // it is compared at the beginning of the path, and if so, it is assumed to issue certain commands + // It's purpose is to protect, to some degree the command, even though it is HTTP, allowing + // local batch files to, for instance, clear caches on resetting of files. + private String clear_command; + + public CachingFileAccess(EnvJAXB env, String ... args) throws IOException { + super(null,"Caching File Access"); + setEnv(env,args); + content = new ConcurrentSkipListMap(); // multi-thread changes possible + + attachOnly = new HashSet(); // short, unchanged + + typeMap = new TreeMap(); // Structure unchanged after Construction + typeMap.put("ico","image/icon"); + typeMap.put("html","text/html"); + typeMap.put("css","text/css"); + typeMap.put("js","text/javascript"); + typeMap.put("txt","text/plain"); + typeMap.put("xml","text/xml"); + typeMap.put("xsd","text/xml"); + attachOnly.add("xsd"); + typeMap.put("crl", "application/x-pkcs7-crl"); + typeMap.put("appcache","text/cache-manifest"); + + typeMap.put("json","text/json"); + typeMap.put("ogg", "audio/ogg"); + typeMap.put("jpg","image/jpeg"); + typeMap.put("gif","image/gif"); + typeMap.put("png","image/png"); + typeMap.put("svg","image/svg+xml"); + typeMap.put("jar","application/x-java-applet"); + typeMap.put("jnlp", "application/x-java-jnlp-file"); + typeMap.put("class", "application/java"); + typeMap.put("props", "text/plain"); + typeMap.put("jks", "application/octet-stream"); + + timer = new Timer("Caching Cleanup",true); + timer.schedule(new Cleanup(content,500),60000,60000); + + // Property params + web_path = env.get(env.staticSlot(CFA_WEB_PATH)); + env.init().log("CachingFileAccess path: " + new File(web_path).getCanonicalPath()); + Object obj; + obj = env.get(env.staticSlot(CFA_CACHE_CHECK_INTERVAL),600000L); // Default is 10 mins + if(obj instanceof Long) {checkInterval=(Long)obj; + } else {checkInterval=Long.parseLong((String)obj);} + + obj = env.get(env.staticSlot(CFA_MAX_SIZE), 512000); // Default is max file 500k + if(obj instanceof Integer) {maxItemSize=(Integer)obj; + } else {maxItemSize =Integer.parseInt((String)obj);} + + clear_command = env.getProperty(CFA_CLEAR_COMMAND,null); + } + + + + @Override + public void handle(TRANS trans, HttpServletRequest req, HttpServletResponse resp) throws IOException { + String key = pathParam(req, ":key"); + String cmd = pathParam(req,":cmd"); + System.out.print(key + clear_command); + if(key.equals(clear_command)) { + resp.setHeader("Content-Type",typeMap.get("txt")); + if("clear".equals(cmd)) { + content.clear(); + resp.setStatus(200/*HttpStatus.OK_200*/); + } else { + resp.setStatus(400/*HttpStatus.BAD_REQUEST_400 */); + } + return; + } + Content c = load(logT , web_path,cmd!=null && cmd.length()>0?key+'/'+cmd:key, null, checkInterval); + if(c.attachmentOnly) { + resp.setHeader("Content-disposition", "attachment"); + } + c.setHeader(resp); + c.write(resp.getOutputStream()); + trans.checkpoint(req.getPathInfo()); + } + + + public String webPath() { + return web_path; + } + + /** + * Reset the Cleanup size and interval + * + * The size and interval when started are 500 items (memory size unknown) checked every minute in a background thread. + * + * @param size + * @param interval + */ + public void cleanupParams(int size, long interval) { + timer.cancel(); + timer = new Timer(); + timer.schedule(new Cleanup(content,size), interval, interval); + } + + + + /** + * Load a file, first checking cache + * + * + * @param logTarget - logTarget can be null (won't log) + * @param dataRoot - data root storage directory + * @param key - relative File Path + * @param mediaType - what kind of file is it. If null, will check via file extension + * @param timeCheck - "-1" will take system default - Otherwise, will compare "now" + timeCheck(Millis) before looking at File mod + * @return + * @throws IOException + */ + public Content load(LogTarget logTarget, String dataRoot, String key, String mediaType, long _timeCheck) throws IOException { + long timeCheck = _timeCheck; + if(timeCheck<0) { + timeCheck=checkInterval; // if time < 0, then use default + } + boolean isRoot; + String fileName; + if("-".equals(key)) { + fileName = dataRoot; + isRoot = true; + } else { + fileName=dataRoot + '/' + key; + isRoot = false; + } + Content c = content.get(key); + long systime = System.currentTimeMillis(); + File f=null; + if(c!=null) { + // Don't check every hit... only after certain time value + if(c.date < systime + timeCheck) { + f = new File(fileName); + if(f.lastModified()>c.date) { + c=null; + } + } + } + if(c==null) { + if(logTarget!=null) { + logTarget.log("File Read: ",key); + } + + if(f==null){ + f = new File(fileName); + } + boolean cacheMe; + if(f.exists()) { + if(f.isDirectory()) { + cacheMe = false; + c = new DirectoryContent(f,isRoot); + } else { + if(f.length() > maxItemSize) { + c = new DirectFileContent(f); + cacheMe = false; + } else { + c = new CachedContent(f); + cacheMe = checkInterval>0; + } + + if(mediaType==null) { // determine from file Ending + int idx = key.lastIndexOf('.'); + String subkey = key.substring(++idx); + if((c.contentType = idx<0?null:typeMap.get(subkey))==null) { + // if nothing else, just set to default type... + c.contentType = "application/octet-stream"; + } + c.attachmentOnly = attachOnly.contains(subkey); + } else { + c.contentType=mediaType; + c.attachmentOnly = false; + } + + c.date = f.lastModified(); + + if(cacheMe) { + content.put(key, c); + } + } + } else { + c=NULL; + } + } else { + if(logTarget!=null)logTarget.log("Cache Read: ",key); + } + + // refresh hit time + c.access = systime; + return c; + } + + public Content loadOrDefault(Trans trans, String targetDir, String targetFileName, String sourcePath, String mediaType) throws IOException { + try { + return load(trans.info(),targetDir,targetFileName,mediaType,0); + } catch(FileNotFoundException e) { + String targetPath = targetDir + '/' + targetFileName; + TimeTaken tt = trans.start("File doesn't exist; copy " + sourcePath + " to " + targetPath, Env.SUB); + try { + FileInputStream sourceFIS = new FileInputStream(sourcePath); + FileChannel sourceFC = sourceFIS.getChannel(); + File targetFile = new File(targetPath); + targetFile.getParentFile().mkdirs(); // ensure directory exists + FileOutputStream targetFOS = new FileOutputStream(targetFile); + try { + ByteBuffer bb = ByteBuffer.allocate((int)sourceFC.size()); + sourceFC.read(bb); + bb.flip(); // ready for reading + targetFOS.getChannel().write(bb); + } finally { + sourceFIS.close(); + targetFOS.close(); + } + } finally { + tt.done(); + } + return load(trans.info(),targetDir,targetFileName,mediaType,0); + } + } + + public void invalidate(String key) { + content.remove(key); + } + + private static final Content NULL=new Content() { + + @Override + public void setHeader(HttpServletResponse resp) { + resp.setStatus(404/*NOT_FOUND_404*/); + resp.setHeader("Content-type","text/plain"); + } + + @Override + public void write(Writer writer) throws IOException { + } + + @Override + public void write(OutputStream os) throws IOException { + } + + }; + + private static abstract class Content { + private long date; // date of the actual artifact (i.e. File modified date) + private long access; // last accessed + + protected String contentType; + protected boolean attachmentOnly; + + public void setHeader(HttpServletResponse resp) { + resp.setStatus(200/*OK_200*/); + resp.setHeader("Content-Type",contentType); + resp.setHeader("Cache-Control", MAX_AGE); + } + + public abstract void write(Writer writer) throws IOException; + public abstract void write(OutputStream os) throws IOException; + + } + + private static class DirectFileContent extends Content { + private File file; + public DirectFileContent(File f) { + file = f; + } + + public String toString() { + return file.getName(); + } + + public void write(Writer writer) throws IOException { + FileReader fr = new FileReader(file); + char[] buff = new char[1024]; + try { + int read; + while((read = fr.read(buff,0,1024))>=0) { + writer.write(buff,0,read); + } + } finally { + fr.close(); + } + } + + public void write(OutputStream os) throws IOException { + FileInputStream fis = new FileInputStream(file); + byte[] buff = new byte[1024]; + try { + int read; + while((read = fis.read(buff,0,1024))>=0) { + os.write(buff,0,read); + } + } finally { + fis.close(); + } + } + + } + private static class DirectoryContent extends Content { + private static final Pattern A_NUMBER = Pattern.compile("\\d"); + private static final String H1 = "AAF Fileserver

AAF Fileserver

"; + private static final String H2 = "

    \n"; + private static final String F = "\n
"; + private File[] files; + private String name; + private boolean notRoot; + + public DirectoryContent(File directory, boolean isRoot) { + notRoot = !isRoot; + + files = directory.listFiles(); + Arrays.sort(files,new Comparator() { + @Override + public int compare(File f1, File f2) { + // See if there are Numbers in the name + Matcher m1 = A_NUMBER.matcher(f1.getName()); + Matcher m2 = A_NUMBER.matcher(f2.getName()); + if(m1.find() && m2.find()) { + // if numbers, are the numbers in the same start position + int i1 = m1.start(); + int i2 = m2.start(); + + // If same start position and the text is the same, then reverse sort + if(i1==i2 && f1.getName().startsWith(f2.getName().substring(0,i1))) { + // reverse sort files that start similarly, but have numbers in them + return f2.compareTo(f1); + } + } + return f1.compareTo(f2); + } + + }); + name = directory.getName(); + attachmentOnly = false; + contentType = "text/html"; + } + + + @Override + public void write(Writer w) throws IOException { + w.append(H1); + w.append(name); + w.append(H2); + for (File f : files) { + w.append("
  • "); + w.append(f.getName()); + w.append("
  • \n"); + } + w.append(F); + w.flush(); + } + + @Override + public void write(OutputStream os) throws IOException { + write(new OutputStreamWriter(os)); + } + + } + + private static class CachedContent extends Content { + private byte[] data; + private int end; + private char[] cdata; + + public CachedContent(File f) throws IOException { + // Read and Cache + ByteBuffer bb = ByteBuffer.allocate((int)f.length()); + FileInputStream fis = new FileInputStream(f); + try { + fis.getChannel().read(bb); + } finally { + fis.close(); + } + + data = bb.array(); + end = bb.position(); + cdata=null; + } + + public String toString() { + return data.toString(); + } + + public void write(Writer writer) throws IOException { + synchronized(this) { + // do the String Transformation once, and only if actually used + if(cdata==null) { + cdata = new char[end]; + new String(data).getChars(0, end, cdata, 0); + } + } + writer.write(cdata,0,end); + } + public void write(OutputStream os) throws IOException { + os.write(data,0,end); + } + + } + + public void setEnv(LogTarget env) { + logT = env; + } + + /** + * Cleanup thread to remove older items if max Cache is reached. + * @author Jonathan + * + */ + private static class Cleanup extends TimerTask { + private int maxSize; + private NavigableMap content; + + public Cleanup(NavigableMap content, int size) { + maxSize = size; + this.content = content; + } + + private class Comp implements Comparable { + public Map.Entry entry; + + public Comp(Map.Entry en) { + entry = en; + } + + @Override + public int compareTo(Comp o) { + return (int)(entry.getValue().access-o.entry.getValue().access); + } + + } + @SuppressWarnings("unchecked") + @Override + public void run() { + int size = content.size(); + if(size>maxSize) { + ArrayList scont = new ArrayList(size); + Object[] entries = content.entrySet().toArray(); + for(int i=0;i)entries[i])); + } + Collections.sort(scont); + int end = size - ((maxSize/4)*3); // reduce to 3/4 of max size + System.out.println("------ Cleanup Cycle ------ " + new Date().toString() + " -------"); + for(int i=0;i entry = scont.get(i).entry; + content.remove(entry.getKey()); + System.out.println("removed Cache Item " + entry.getKey() + "/" + new Date(entry.getValue().access).toString()); + } + for(int i=end;i entry = scont.get(i).entry; + System.out.println("remaining Cache Item " + entry.getKey() + "/" + new Date(entry.getValue().access).toString()); + } + } + } + } +} diff --git a/auth/auth-core/src/main/java/org/onap/aaf/auth/rserv/CodeSetter.java b/auth/auth-core/src/main/java/org/onap/aaf/auth/rserv/CodeSetter.java new file mode 100644 index 00000000..6ea8880b --- /dev/null +++ b/auth/auth-core/src/main/java/org/onap/aaf/auth/rserv/CodeSetter.java @@ -0,0 +1,52 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.rserv; + +import java.io.IOException; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.onap.aaf.misc.env.Trans; + +// Package on purpose. only want between RServlet and Routes +class CodeSetter { + private HttpCode code; + private TRANS trans; + private HttpServletRequest req; + private HttpServletResponse resp; + public CodeSetter(TRANS trans, HttpServletRequest req, HttpServletResponse resp) { + this.trans = trans; + this.req = req; + this.resp = resp; + + } + public boolean matches(Route route) throws IOException, ServletException { + // Find best Code in Route based on "Accepts (Get) or Content-Type" (if exists) + return (code = route.getCode(trans, req, resp))!=null; + } + + public HttpCode code() { + return code; + } +} \ No newline at end of file diff --git a/auth/auth-core/src/main/java/org/onap/aaf/auth/rserv/Content.java b/auth/auth-core/src/main/java/org/onap/aaf/auth/rserv/Content.java new file mode 100644 index 00000000..ae329ce2 --- /dev/null +++ b/auth/auth-core/src/main/java/org/onap/aaf/auth/rserv/Content.java @@ -0,0 +1,115 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.rserv; + +import java.util.List; + +import org.onap.aaf.misc.env.Trans; + + + +/** + * A Class to hold Service "ContentTypes", and to match incoming "Accept" types from HTTP. + * + * This is a multi-use class built to use the same Parser for ContentTypes and Accept. + * + * Thus, you would create and use "Content.Type" within your service, and use it to match + * Accept Strings. What is returned is an Integer (for faster processing), which can be + * used in a switch statement to act on match different Actions. The server should + * know which behaviors match. + * + * "bestMatch" returns an integer for the best match, or -1 if no matches. + * + * @author Jonathan + * + */ +public abstract class Content { + public static final String Q = "q"; + protected abstract Pair,List>>> types(HttpCode code, String str); + protected abstract boolean props(Pair,List>>> type, String tag, String value); + + /** + * Parse a Content-Type/Accept. As found, call "types" and "props", which do different + * things depending on if it's a Content-Type or Accepts. + * + * For Content-Type, it builds a tree suitable for Comparison + * For Accepts, it compares against the tree, and builds an acceptable type list + * + * Since this parse code is used for every incoming HTTP transaction, I have removed the implementation + * that uses String.split, and replaced with integers evaluating the Byte array. This results + * in only the necessary strings created, resulting in 1/3 better speed, and less + * Garbage collection. + * + * @param trans + * @param code + * @param cntnt + * @return + */ + protected boolean parse(HttpCode code, String cntnt) { + byte bytes[] = cntnt.getBytes(); + boolean contType=false,contProp=true; + int cis,cie=-1,cend; + int sis,sie,send; + do { + cis = cie+1; + cie = cntnt.indexOf(',',cis); + cend = cie<0?bytes.length:cie; + // Start SEMIS + sie=cis-1; + Pair, List>>> me = null; + do { + sis = sie+1; + sie = cntnt.indexOf(';',sis); + send = sie>cend || sie<0?cend:sie; + if(me==null) { + String semi = new String(bytes,sis,send-sis); + // trans.checkpoint(semi); + // Look at first entity within comma group + // Is this an acceptable Type? + me=types(code, semi); + if(me==null) { + sie=-1; // skip the rest of the processing... not a type + } else { + contType=true; + } + } else { // We've looped past the first Semi, now process as properties + // If there are additional elements (more entities within Semi Colons) + // apply Propertys + int eq = cntnt.indexOf('=',sis); + if(eq>sis && eq + * @param + */ +public abstract class HttpCode { + protected CONTEXT context; + private String desc; + protected String [] roles; + private boolean all; + + // Package by design... Set by Route when linked + Match match; + + public HttpCode(CONTEXT context, String description, String ... roles) { + this.context = context; + desc = description; + + // Evaluate for "*" once... + all = false; + for(String srole : roles) { + if("*".equals(srole)) { + all = true; + break; + } + } + this.roles = all?null:roles; + } + + public abstract void handle(TRANS trans, HttpServletRequest req, HttpServletResponse resp) throws Exception; + + public String desc() { + return desc; + } + + /** + * Get the variable element out of the Path Parameter, as set by initial Code + * + * @param req + * @param key + * @return + */ + public String pathParam(HttpServletRequest req, String key) { + String rv = match.param(req.getPathInfo(), key); + if(rv!=null) { + rv = rv.trim(); + if(rv.endsWith("/")) { + rv = rv.substring(0, rv.length()-1); + } + } + return rv; + } + + // Note: get Query Params from Request + + /** + * Check for Authorization when set. + * + * If no Roles set, then accepts all users + * + * @param req + * @return + */ + public boolean isAuthorized(HttpServletRequest req) { + if(all)return true; + if(roles!=null) { + for(String srole : roles) { + if(req.isUserInRole(srole)) return true; + } + } + return false; + } + + public boolean no_cache() { + return false; + } + + public String toString() { + return desc; + } +} \ No newline at end of file diff --git a/auth/auth-core/src/main/java/org/onap/aaf/auth/rserv/HttpMethods.java b/auth/auth-core/src/main/java/org/onap/aaf/auth/rserv/HttpMethods.java new file mode 100644 index 00000000..4dbaf17b --- /dev/null +++ b/auth/auth-core/src/main/java/org/onap/aaf/auth/rserv/HttpMethods.java @@ -0,0 +1,29 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.rserv; + +public enum HttpMethods { + POST, + GET, + PUT, + DELETE +} diff --git a/auth/auth-core/src/main/java/org/onap/aaf/auth/rserv/Match.java b/auth/auth-core/src/main/java/org/onap/aaf/auth/rserv/Match.java new file mode 100644 index 00000000..ac8b31c1 --- /dev/null +++ b/auth/auth-core/src/main/java/org/onap/aaf/auth/rserv/Match.java @@ -0,0 +1,211 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.rserv; + +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +/** + * This path matching algorithm avoids using split strings during the critical transactional run-time. By pre-analyzing the + * content at "set Param" time, and storing data in an array-index model which presumably is done once and at the beginning, + * we can match in much less time when it actually counts. + * + * @author Jonathan + * + */ +public class Match { + private Map params; + private byte[] values[]; + private Integer vars[]; + private boolean wildcard; + + + /* + * These two methods are pairs of searching performance for variables Spark Style. + * setParams evaluates the target path, and sets a HashMap that will return an Integer. + * the Keys are both :key and key so that there will be no string operations during + * a transaction + * + * For the Integer, if the High Order is 0, then it is just one value. If High Order >0, then it is + * a multi-field option, i.e. ending with a wild-card. + */ + public Match(String path) { + // IF DEBUG: System.out.print("\n[" + path + "]"); + params = new HashMap(); + if(path!=null) { + String[] pa = path.split("/"); + values = new byte[pa.length][]; + vars = new Integer[pa.length]; + + int val = 0; + String key; + for(int i=0;i1) { + /* remove * from value */ + int newlength = values[i].length-1; + byte[] real = new byte[newlength]; + System.arraycopy(values[i],0,real,0,newlength); + values[i]=real; + } else { + vars[i]=0; // this is actually a variable, if it only contains a "*" + } + } + // vars[i]=null; + } + } + } + } + + /* + * This is the second of the param evaluation functions. First, we look up to see if there is + * any reference by key in the params Map created by the above. + * + * The resulting Integer, if not null, is split high/low order into start and end. + * We evaluate the string for '/', rather than splitting into String[] to avoid the time/mem needed + * We traverse to the proper field number for slash, evaluate the end (whether wild card or no), + * and return the substring. + * + * The result is something less than .003 milliseconds per evaluation + * + */ + public String param(String path,String key) { + Integer val = params.get(key); // :key or key + if(val!=null) { + int start = val & 0xFFFF; + int end = (val >> 16) & 0xFFFF; + int idx = -1; + int i; + for(i=0;i0?(pabytes[0]=='/'):false; + // IF DEBUG: System.out.println("\n -- " + path + " --"); + for(int i=0;rv && i=lastField) { // checking here allows there to be a non-functional ending / + rv = false; + break; + } + if(values[field]==null) { // it's a variable, just look for /s + if(wildcard && field==lastField-1) return true;// we've made it this far. We accept all remaining characters + Integer val = vars[field]; + int start = val & 0xFFFF; + int end = (val >> 16) & 0xFFFF; + if(end==0)end=start+1; + int k = i; + for(int j=start; ji)i=k-1; // if we've incremented, have to accommodate the outer for loop incrementing as well + fieldMatched = false; // reset + fieldIdx = 0; + } else { + // IF DEBUG: System.out.print((char)pabytes[i]); + if(pabytes[i]=='/') { // end of field, eval if Field is matched + // if double slash, check if supposed to be empty + if(fieldIdx==0 && values[field].length==0) { + fieldMatched = true; + } + rv = fieldMatched && ++field getParamNames() { + return params.keySet(); + } +} \ No newline at end of file diff --git a/auth/auth-core/src/main/java/org/onap/aaf/auth/rserv/Pair.java b/auth/auth-core/src/main/java/org/onap/aaf/auth/rserv/Pair.java new file mode 100644 index 00000000..810f9129 --- /dev/null +++ b/auth/auth-core/src/main/java/org/onap/aaf/auth/rserv/Pair.java @@ -0,0 +1,44 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.rserv; + +/** + * A pair of generic Objects. + * + * @author Jonathan + * + * @param + * @param + */ +public class Pair { + public X x; + public Y y; + + public Pair(X x, Y y) { + this.x = x; + this.y = y; + } + + public String toString() { + return "X: " + x.toString() + "-->" + y.toString(); + } +} diff --git a/auth/auth-core/src/main/java/org/onap/aaf/auth/rserv/RServlet.java b/auth/auth-core/src/main/java/org/onap/aaf/auth/rserv/RServlet.java new file mode 100644 index 00000000..4ae0f882 --- /dev/null +++ b/auth/auth-core/src/main/java/org/onap/aaf/auth/rserv/RServlet.java @@ -0,0 +1,154 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.rserv; + +import java.io.IOException; +import java.util.List; + +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; + +import org.onap.aaf.misc.env.Env; +import org.onap.aaf.misc.env.TimeTaken; +import org.onap.aaf.misc.env.Trans; + +public abstract class RServlet implements Servlet { + private Routes routes = new Routes(); + + private ServletConfig config; + + @Override + public void init(ServletConfig config) throws ServletException { + this.config = config; + } + + @Override + public ServletConfig getServletConfig() { + return config; + } + + public void route(Env env, HttpMethods meth, String path, HttpCode code, String ... moreTypes) { + Route r = routes.findOrCreate(meth,path); + r.add(code,moreTypes); + env.init().log(r.report(code),code); + } + + @Override + public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException { + HttpServletRequest request = (HttpServletRequest)req; + HttpServletResponse response = (HttpServletResponse)res; + + @SuppressWarnings("unchecked") + TRANS trans = (TRANS)req.getAttribute(TransFilter.TRANS_TAG); + if(trans==null) { + response.setStatus(404); // Not Found, because it didn't go through TransFilter + return; + } + + Route route; + HttpCode code=null; + String ct = req.getContentType(); + TimeTaken tt = trans.start("Resolve to Code", Env.SUB); + try { + // routes have multiple code sets. This object picks the best code set + // based on Accept or Content-Type + CodeSetter codesetter = new CodeSetter(trans,request,response); + // Find declared route + route = routes.derive(request, codesetter); + if(route==null) { + String method = request.getMethod(); + trans.checkpoint("No Route matches "+ method + ' ' + request.getPathInfo()); + response.setStatus(404); // Not Found + } else { + // Find best Code in Route based on "Accepts (Get) or Content-Type" (if exists) + code = codesetter.code();// route.getCode(trans, request, response); + } + } finally { + tt.done(); + } + + if(route!=null && code!=null) { + StringBuilder sb = new StringBuilder(72); + sb.append(route.auditText); + sb.append(','); + sb.append(code.desc()); + if(ct!=null) { + sb.append(", ContentType: "); + sb.append(ct); + } + tt = trans.start(sb.toString(),Env.SUB); + try { + /*obj = */ + code.handle(trans, request, response); + response.flushBuffer(); + } catch (ServletException e) { + trans.error().log(e); + throw e; + } catch (Exception e) { + trans.error().log(e,request.getMethod(),request.getPathInfo()); + throw new ServletException(e); + } finally { + tt.done(); + } + } + } + + @Override + public String getServletInfo() { + return "RServlet for Jetty"; + } + + @Override + public void destroy() { + } + + public String applicationJSON(Class cls, String version) { + StringBuilder sb = new StringBuilder(); + sb.append("application/"); + sb.append(cls.getSimpleName()); + sb.append("+json"); + sb.append(";charset=utf-8"); + sb.append(";version="); + sb.append(version); + return sb.toString(); + } + + public String applicationXML(Class cls, String version) { + StringBuilder sb = new StringBuilder(); + sb.append("application/"); + sb.append(cls.getSimpleName()); + sb.append("+xml"); + sb.append(";charset=utf-8"); + sb.append(";version="); + sb.append(version); + return sb.toString(); + } + + public List routeReport() { + return routes.routeReport(); + } +} diff --git a/auth/auth-core/src/main/java/org/onap/aaf/auth/rserv/Route.java b/auth/auth-core/src/main/java/org/onap/aaf/auth/rserv/Route.java new file mode 100644 index 00000000..9ae202a2 --- /dev/null +++ b/auth/auth-core/src/main/java/org/onap/aaf/auth/rserv/Route.java @@ -0,0 +1,141 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.rserv; + +import java.io.IOException; +import java.util.List; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.onap.aaf.misc.env.Env; +import org.onap.aaf.misc.env.TimeTaken; +import org.onap.aaf.misc.env.Trans; + +public class Route { + public final String auditText; + public final HttpMethods meth; + public final String path; + + private Match match; + // package on purpose + private final TypedCode content; + private final boolean isGet; + + public Route(HttpMethods meth, String path) { + this.path = path; + auditText = meth.name() + ' ' + path; + this.meth = meth; // Note: Using Spark def for now. + isGet = meth.compareTo(HttpMethods.GET) == 0; + match = new Match(path); + content = new TypedCode(); + } + + public void add(HttpCode code, String ... others) { + code.match = match; + content.add(code, others); + } + +// public void add(HttpCode code, Class cls, String version, String ... others) { +// code.match = match; +// content.add(code, cls, version, others); +// } +// + public HttpCode getCode(TRANS trans, HttpServletRequest req, HttpServletResponse resp) throws IOException, ServletException { + // Type is associated with Accept for GET (since it is what is being returned + // We associate the rest with ContentType. + // FYI, thought about this a long time before implementing this way. + String compare; +// String special[]; // todo, expose Charset (in special) to outside + if(isGet) { + compare = req.getHeader("Accept"); // Accept is used for read, as we want to agree on what caller is ready to handle + } else { + compare = req.getContentType(); // Content type used to declare what data is being created, updated or deleted (might be used for key) + } + + Pair, List>>> hl = content.prep(trans, compare); + if(hl==null) { + resp.setStatus(406); // NOT_ACCEPTABLE + } else { + if(isGet) { // Set Content Type to expected content + if("*".equals(hl.x) || "*/*".equals(hl.x)) {// if wild-card, then choose first kind of type + resp.setContentType(content.first()); + } else { + resp.setContentType(hl.x); + } + } + return hl.y.x; + } + return null; + } + + public Route matches(String method, String path) { + return meth.name().equalsIgnoreCase(method) && match.match(path)?this:null; + } + + public TimeTaken start(Trans trans, String auditText, HttpCode code, String type) { + StringBuilder sb = new StringBuilder(auditText); + sb.append(", "); + sb.append(code.desc()); + sb.append(", Content: "); + sb.append(type); + return trans.start(sb.toString(), Env.SUB); + } + + // Package on purpose.. for "find/Create" routes only + boolean resolvesTo(HttpMethods hm, String p) { + return(path.equals(p) && hm.equals(meth)); + } + + public String toString() { + return auditText + ' ' + content; + } + + public String report(HttpCode code) { + StringBuilder sb = new StringBuilder(); + sb.append(auditText); + sb.append(' '); + content.relatedTo(code, sb); + return sb.toString(); + } + + public RouteReport api() { + RouteReport tr = new RouteReport(); + tr.meth = meth; + tr.path = path; + content.api(tr); + return tr; + } + + + /** + * contentRelatedTo (For reporting) list routes that will end up at a specific Code + * @return + */ + public String contentRelatedTo(HttpCode code) { + StringBuilder sb = new StringBuilder(path); + sb.append(' '); + content.relatedTo(code, sb); + return sb.toString(); + } +} diff --git a/auth/auth-core/src/main/java/org/onap/aaf/auth/rserv/RouteReport.java b/auth/auth-core/src/main/java/org/onap/aaf/auth/rserv/RouteReport.java new file mode 100644 index 00000000..5de2ebe3 --- /dev/null +++ b/auth/auth-core/src/main/java/org/onap/aaf/auth/rserv/RouteReport.java @@ -0,0 +1,33 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.rserv; + +import java.util.ArrayList; +import java.util.List; + +public class RouteReport { + public HttpMethods meth; + public String path; + public String desc; + public final List contextTypes = new ArrayList(); + +} diff --git a/auth/auth-core/src/main/java/org/onap/aaf/auth/rserv/Routes.java b/auth/auth-core/src/main/java/org/onap/aaf/auth/rserv/Routes.java new file mode 100644 index 00000000..fefb8f3c --- /dev/null +++ b/auth/auth-core/src/main/java/org/onap/aaf/auth/rserv/Routes.java @@ -0,0 +1,89 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.rserv; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; + +import org.onap.aaf.misc.env.Trans; + + +public class Routes { + // Since this must be very, very fast, and only needs one creation, we'll use just an array. + private Route[] routes; + private int end; + + + @SuppressWarnings("unchecked") + public Routes() { + routes = new Route[10]; + end = 0; + } + + // This method for setup of Routes only... + // Package on purpose + synchronized Route findOrCreate(HttpMethods meth, String path) { + Route rv = null; + for(int i=0;i=routes.length) { + @SuppressWarnings("unchecked") + Route[] temp = new Route[end+10]; + System.arraycopy(routes, 0, temp, 0, routes.length); + routes = temp; + } + + routes[end++]=rv=new Route(meth,path); + } + return rv; + } + + public Route derive(HttpServletRequest req, CodeSetter codeSetter) throws IOException, ServletException { + Route rv = null; + String path = req.getPathInfo(); + String meth = req.getMethod(); + //TODO a TREE would be better + for(int i=0;rv==null && i routeReport() { + ArrayList ltr = new ArrayList(); + for(int i=0;i implements Filter { + public static final String TRANS_TAG = "__TRANS__"; + + private CadiHTTPManip cadi; + + private final String[] no_authn; + + public TransFilter(Access access, Connector con, TrustChecker tc, Object ... additionalTafLurs) throws CadiException { + cadi = new CadiHTTPManip(access, con, tc, additionalTafLurs); + String no = access.getProperty(Config.CADI_NOAUTHN, null); + if(no!=null) { + no_authn = Split.split(':', no); + } else { + no_authn=null; + } + } + + @Override + public void init(FilterConfig filterConfig) throws ServletException { + } + + protected Lur getLur() { + return cadi.getLur(); + } + + protected abstract TRANS newTrans(); + protected abstract TimeTaken start(TRANS trans, ServletRequest request); + protected abstract void authenticated(TRANS trans, Principal p); + protected abstract void tallyHo(TRANS trans); + + @Override + public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { + TRANS trans = newTrans(); + + TimeTaken overall = start(trans,request); + try { + request.setAttribute(TRANS_TAG, trans); + + HttpServletRequest req = (HttpServletRequest)request; + HttpServletResponse res = (HttpServletResponse)response; + + if(no_authn!=null) { + for(String prefix : no_authn) { + if(req.getPathInfo().startsWith(prefix)) { + chain.doFilter(request, response); + return; + } + } + } + + TimeTaken security = trans.start("CADI Security", Env.SUB); + TafResp resp; + RESP r; + CadiWrap cw = null; + try { + resp = cadi.validate(req,res,trans); + switch(r=resp.isAuthenticated()) { + case IS_AUTHENTICATED: + cw = new CadiWrap(req,resp,cadi.getLur()); + authenticated(trans, cw.getUserPrincipal()); + break; + default: + break; + } + } finally { + security.done(); + } + + if(r==RESP.IS_AUTHENTICATED) { + trans.checkpoint(resp.desc()); + if(cadi.notCadi(cw, res)) { + chain.doFilter(cw, response); + } + } else { + //TODO this is a good place to check if too many checks recently + // Would need Cached Counter objects that are cleaned up on + // use + trans.checkpoint(resp.desc(),Env.ALWAYS); + if(resp.isFailedAttempt()) + trans.audit().log(resp.desc()); + } + } catch(Exception e) { + trans.error().log(e); + trans.checkpoint("Error: " + e.getClass().getSimpleName() + ": " + e.getMessage()); + throw new ServletException(e); + } finally { + overall.done(); + tallyHo(trans); + } + } + + @Override + public void destroy() { + }; +} diff --git a/auth/auth-core/src/main/java/org/onap/aaf/auth/rserv/TransOnlyFilter.java b/auth/auth-core/src/main/java/org/onap/aaf/auth/rserv/TransOnlyFilter.java new file mode 100644 index 00000000..e0f7512d --- /dev/null +++ b/auth/auth-core/src/main/java/org/onap/aaf/auth/rserv/TransOnlyFilter.java @@ -0,0 +1,77 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.rserv; + +import java.io.IOException; + +import javax.servlet.Filter; +import javax.servlet.FilterChain; +import javax.servlet.FilterConfig; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; + +import org.onap.aaf.cadi.principal.TaggedPrincipal; +import org.onap.aaf.misc.env.TimeTaken; +import org.onap.aaf.misc.env.TransStore; + +/** + * Create a new Transaction Object for each and every incoming Transaction + * + * Attach to Request. User "FilterHolder" mechanism to retain single instance. + * + * TransFilter includes CADIFilter as part of the package, so that it can + * set User Data, etc, as necessary. + * + * @author Jonathan + * + */ +public abstract class TransOnlyFilter implements Filter { + @Override + public void init(FilterConfig filterConfig) throws ServletException { + } + + + + protected abstract TRANS newTrans(); + protected abstract TimeTaken start(TRANS trans, ServletRequest request); + protected abstract void authenticated(TRANS trans, TaggedPrincipal p); + protected abstract void tallyHo(TRANS trans); + + @Override + public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { + TRANS trans = newTrans(); + + TimeTaken overall = start(trans,request); + try { + request.setAttribute(TransFilter.TRANS_TAG, trans); + chain.doFilter(request, response); + } finally { + overall.done(); + } + tallyHo(trans); + } + + @Override + public void destroy() { + }; +} diff --git a/auth/auth-core/src/main/java/org/onap/aaf/auth/rserv/TypedCode.java b/auth/auth-core/src/main/java/org/onap/aaf/auth/rserv/TypedCode.java new file mode 100644 index 00000000..82b291c7 --- /dev/null +++ b/auth/auth-core/src/main/java/org/onap/aaf/auth/rserv/TypedCode.java @@ -0,0 +1,269 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.rserv; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; + +import javax.servlet.ServletException; + +import org.onap.aaf.misc.env.Env; +import org.onap.aaf.misc.env.TimeTaken; +import org.onap.aaf.misc.env.Trans; + + +/** + * TypedCode organizes implementation code based on the Type and Version of code it works with so that it can + * be located quickly at runtime based on the "Accept" HTTP Header. + * + * FYI: For those in the future wondering why I would create a specialized set of "Pair" for the data content: + * 1) TypeCode is used in Route, and this code is used for every transaction... it needs to be blazingly fast + * 2) The actual number of objects accessed is quite small and built at startup. Arrays are best + * 3) I needed a small, well defined tree where each level is a different Type. Using a "Pair" Generic definitions, + * I created type-safety at each level, which you can't get from a TreeSet, etc. + * 4) Chaining through the Network is simply object dereferencing, which is as fast as Java can go. + * 5) The drawback is that in your code is that all the variables are named "x" and "y", which can be a bit hard to + * read both in code, and in the debugger. However, TypeSafety allows your IDE (Eclipse) to help you make the + * choices. Also, make sure you have a good "toString()" method on each object so you can see what's happening + * in the IDE Debugger. + * + * Empirically, this method of obtaining routes proved to be much faster than the HashSet implementations available in otherwise + * competent Open Source. + * + * @author Jonathan + * + * @param + */ +public class TypedCode extends Content { + private List,List>>>> types; + + public TypedCode() { + types = new ArrayList,List>>>>(); + } + + /** + * Construct Typed Code based on ContentType parameters passed in + * + * @param code + * @param others + * @return + */ + public TypedCode add(HttpCode code, String ... others) { + StringBuilder sb = new StringBuilder(); + boolean first = true; + for(String str : others) { + if(first) { + first = false; + } else { + sb.append(','); + } + sb.append(str); + } + parse(code, sb.toString()); + + return this; + } + + @Override + protected Pair, List>>> types(HttpCode code, String str) { + Pair,List>>> type = null; + ArrayList> props = new ArrayList>(); + // Want Q percentage is to be first in the array everytime. If not listed, 1.0 is default + props.add(new Pair(Q,1f)); + Pair, List>> cl = new Pair, List>>(code, props); +// // breakup "plus" stuff, i.e. application/xaml+xml +// int plus = str.indexOf('+'); +// if(plus<0) { + type = new Pair,List>>>(str, cl); + types.add(type); + return type; +// } else { +// int prev = str.indexOf('/')+1; +// String first = str.substring(0,prev); +// String nstr; +// while(prev!=0) { +// nstr = first + (plus>-1?str.substring(prev,plus):str.substring(prev)); +// type = new Pair,List>>>(nstr, cl); +// types.add(type); +// prev = plus+1; +// plus = str.indexOf('+',prev); +// } +// return type; +// } + } + + @Override + protected boolean props(Pair, List>>> type, String tag, String value) { + if(tag.equals(Q)) { // reset the Q value (first in array) + boolean rv = true; + try { + type.y.y.get(0).y=Float.parseFloat(value); + return rv; + } catch (NumberFormatException e) { + rv=false; // Note: this awkward syntax forced by Sonar, which doesn't like doing nothing with Exception + // which is what should happen + } + } + return type.y.y.add(new Pair(tag,"version".equals(tag)?new Version(value):value)); + } + + public Pair, List>>> prep(TRANS trans, String compare) throws IOException, ServletException { + Pair, List>>> c,rv=null; + if(types.size()==1 && "".equals((c=types.get(0)).x)) { // if there are no checks for type, skip + rv = c; + } else { + if(compare==null || compare.length()==0) { + rv = types.get(0); // first code is used + } else { + Acceptor acc = new Acceptor(types); + boolean accepted; + TimeTaken tt = trans.start(compare, Env.SUB); + try { + accepted = acc.parse(null, compare); + } finally { + tt.done(); + } + if(accepted) { + switch(acc.acceptable.size()) { + case 0: +// // TODO best Status Code? +// resp.setStatus(HttpStatus.NOT_ACCEPTABLE_406); + break; + case 1: + rv = acc.acceptable.get(0); + break; + default: // compare Q values to get Best Match + float bestQ = -1.0f; + Pair, List>>> bestT = null; + for(Pair, List>>> type : acc.acceptable) { + Float f = (Float)type.y.y.get(0).y; // first property is always Q + if(f>bestQ) { + bestQ=f; + bestT = type; + } + } + if(bestT!=null) { + // When it is a GET, the matched type is what is returned, so set ContentType +// if(isGet)resp.setContentType(bestT.x); // set ContentType of Code +// rv = bestT.y.x; + rv = bestT; + } + } + } else { + trans.checkpoint("No Match found for Accept"); + } + } + } + return rv; + } + + /** + * Print on String Builder content related to specific Code + * + * This is for Reporting and Debugging purposes, so the content is not cached. + * + * If code is "null", then all content is matched + * + * @param code + * @return + */ + public StringBuilder relatedTo(HttpCode code, StringBuilder sb) { + boolean first = true; + for(Pair, List>>> pair : types) { + if(code==null || pair.y.x == code) { + if(first) { + first = false; + } else { + sb.append(','); + } + sb.append(pair.x); + for(Pair prop : pair.y.y) { + // Don't print "Q". it's there for internal use, but it is only meaningful for "Accepts" + if(!prop.x.equals(Q) || !prop.y.equals(1f) ) { + sb.append(';'); + sb.append(prop.x); + sb.append('='); + sb.append(prop.y); + } + } + } + } + return sb; + } + + public List> getContent(HttpCode code) { + for(Pair, List>>> pair : types) { + if(pair.y.x == code) { + return pair.y.y; + } + } + return null; + } + + public String toString() { + return relatedTo(null,new StringBuilder()).toString(); + } + + public void api(RouteReport tr) { + // Need to build up a map, because Prop entries can be in several places. + HashMap,StringBuilder> psb = new HashMap,StringBuilder>(); + StringBuilder temp; + tr.desc = null; + + // Read through Code/TypeCode trees for all accepted Typecodes + for(Pair, List>>> tc : types) { + // If new, then it's new Code set, create prefix content + if((temp=psb.get(tc.y.x))==null) { + psb.put(tc.y.x,temp=new StringBuilder()); + if(tr.desc==null) { + tr.desc = tc.y.x.desc(); + } + } else { + temp.append(','); + } + temp.append(tc.x); + + // add all properties + for(Pair props : tc.y.y) { + temp.append(';'); + temp.append(props.x); + temp.append('='); + temp.append(props.y); + } + } + // Gather all ContentType possibilities for the same code together + + for(StringBuilder sb : psb.values()) { + tr.contextTypes.add(sb.toString()); + } + } + + public String first() { + if(types.size()>0) { + return types.get(0).x; + } + return null; + } + + } \ No newline at end of file diff --git a/auth/auth-core/src/main/java/org/onap/aaf/auth/rserv/Version.java b/auth/auth-core/src/main/java/org/onap/aaf/auth/rserv/Version.java new file mode 100644 index 00000000..ce0981fe --- /dev/null +++ b/auth/auth-core/src/main/java/org/onap/aaf/auth/rserv/Version.java @@ -0,0 +1,93 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.rserv; + + +/** + * Analyze and hold Version information for Code + * + * @author Jonathan + * + */ +public class Version { + private Object[] parts; + + public Version(String v) { + String sparts[] = v.split("\\."); + parts = new Object[sparts.length]; + System.arraycopy(sparts, 0, parts, 0, sparts.length); + if(parts.length>1) { // has at least a minor + try { + parts[1]=Integer.decode(sparts[1]); // minor elements need to be converted to Integer for comparison + } catch (NumberFormatException e) { + // it's ok, leave it as a string + parts[1]=sparts[1]; // This useless piece of code forced by Sonar which calls empty Exceptions "Blockers". + } + } + } + + public boolean equals(Object obj) { + if(obj instanceof Version) { + Version ver = (Version)obj; + int length = Math.min(parts.length, ver.parts.length); + for(int i=0;i extends RServlet { + public final Access access; + public final ENV env; + private AAFConHttp aafCon; + + public final String app_name; + public final String app_version; + public final String app_interface_version; + public final String ROOT_NS; + + public AbsService(final Access access, final ENV env) throws CadiException { + Define.set(access); + ROOT_NS = Define.ROOT_NS(); + this.access = access; + this.env = env; + + String component = access.getProperty(Config.AAF_COMPONENT, null); + final String[] locator_deploy; + + if(component == null) { + locator_deploy = null; + } else { + locator_deploy = Split.splitTrim(':', component); + } + + if(component == null || locator_deploy==null || locator_deploy.length<2) { + throw new CadiException("AAF Component must include the " + Config.AAF_COMPONENT + " property, :[] registrants(final int port) throws CadiException, LocatorException; + + // Lazy Instantiation + public synchronized AAFConHttp aafCon() throws CadiException, LocatorException { + if(aafCon==null) { + if(access.getProperty(Config.AAF_URL,null)!=null) { + aafCon = _newAAFConHttp(); + } else { + throw new CadiException("AAFCon cannot be constructed without " + Config.AAF_URL); + } + } + return aafCon; + } + + /** + * Allow to be over ridden for special cases + * @return + * @throws LocatorException + */ + protected synchronized AAFConHttp _newAAFConHttp() throws CadiException, LocatorException { + try { + if(aafCon==null) { + aafCon = new AAFConHttp(access); + } + return aafCon; + } catch (APIException e) { + throw new CadiException(e); + } + } + + // This is a method, so we can overload for AAFAPI + public String aaf_url() { + return access.getProperty(Config.AAF_URL, null); + } + + public Rcli client() throws CadiException { + return aafCon.client(Config.AAF_DEFAULT_VERSION); + } + + public Rcli clientAsUser(TaggedPrincipal p) throws CadiException { + return aafCon.client(Config.AAF_DEFAULT_VERSION).forUser( + new HTransferSS(p,app_name, aafCon.securityInfo())); + } + + public RET clientAsUser(TaggedPrincipal p,Retryable retryable) throws APIException, LocatorException, CadiException { + return aafCon.hman().best(new HTransferSS(p,app_name, aafCon.securityInfo()), retryable); + } +} diff --git a/auth/auth-core/src/main/java/org/onap/aaf/auth/server/AbsServiceStarter.java b/auth/auth-core/src/main/java/org/onap/aaf/auth/server/AbsServiceStarter.java new file mode 100644 index 00000000..1a6c54d7 --- /dev/null +++ b/auth/auth-core/src/main/java/org/onap/aaf/auth/server/AbsServiceStarter.java @@ -0,0 +1,95 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ +package org.onap.aaf.auth.server; +import org.onap.aaf.auth.org.OrganizationException; +import org.onap.aaf.auth.org.OrganizationFactory; +import org.onap.aaf.auth.rserv.RServlet; +import org.onap.aaf.cadi.Access; +import org.onap.aaf.cadi.register.Registrant; +import org.onap.aaf.cadi.register.Registrar; +import org.onap.aaf.misc.env.Trans; +import org.onap.aaf.misc.rosetta.env.RosettaEnv; + +public abstract class AbsServiceStarter implements ServiceStarter { + private Registrar registrar; + private boolean do_register; + protected AbsService service; + + + public AbsServiceStarter(final AbsService service) { + this.service = service; + try { + OrganizationFactory.init(service.env); + } catch (OrganizationException e) { + service.access.log(e, "Missing defined Organzation Plugins"); + System.exit(3); + } + // do_register - this is used for specialty Debug Situations. Developer can create an Instance for a remote system + // for Debugging purposes without fear that real clients will start to call your debug instance + do_register = !"TRUE".equalsIgnoreCase(access().getProperty("aaf_locate_no_register",null)); + _propertyAdjustment(); + } + + public abstract void _start(RServlet rserv) throws Exception; + public abstract void _propertyAdjustment(); + + public ENV env() { + return service.env; + } + + public Access access() { + return service.access; + } + + @Override + public final void start() throws Exception { + _start(service); + Runtime.getRuntime().addShutdownHook(new Thread() { + @Override + public void run() { + shutdown(); + } + }); + } + + @SafeVarargs + public final synchronized void register(final Registrant ... registrants) { + if(do_register) { + if(registrar==null) { + registrar = new Registrar(env(),false); + } + for(Registrant r : registrants) { + registrar.register(r); + } + } + } + + @Override + public void shutdown() { + if(registrar!=null) { + registrar.close(env()); + registrar=null; + } + if(service!=null) { + service.destroy(); + } + } +} diff --git a/auth/auth-core/src/main/java/org/onap/aaf/auth/server/JettyServiceStarter.java b/auth/auth-core/src/main/java/org/onap/aaf/auth/server/JettyServiceStarter.java new file mode 100644 index 00000000..dbf24cc6 --- /dev/null +++ b/auth/auth-core/src/main/java/org/onap/aaf/auth/server/JettyServiceStarter.java @@ -0,0 +1,255 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ +package org.onap.aaf.auth.server; + +import java.io.IOException; +import java.net.InetAddress; +import java.util.Properties; + +import javax.servlet.Filter; +import javax.servlet.FilterChain; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.eclipse.jetty.http.HttpVersion; +import org.eclipse.jetty.server.HttpConfiguration; +import org.eclipse.jetty.server.HttpConnectionFactory; +import org.eclipse.jetty.server.Request; +import org.eclipse.jetty.server.SecureRequestCustomizer; +import org.eclipse.jetty.server.Server; +import org.eclipse.jetty.server.ServerConnector; +import org.eclipse.jetty.server.SslConnectionFactory; +import org.eclipse.jetty.server.handler.AbstractHandler; +import org.eclipse.jetty.util.ssl.SslContextFactory; +import org.onap.aaf.auth.org.OrganizationException; +import org.onap.aaf.auth.rserv.RServlet; +import org.onap.aaf.cadi.CadiException; +import org.onap.aaf.cadi.LocatorException; +import org.onap.aaf.cadi.Access.Level; +import org.onap.aaf.cadi.config.Config; +import org.onap.aaf.cadi.config.SecurityInfo; +import org.onap.aaf.misc.env.Trans; +import org.onap.aaf.misc.env.util.Split; +import org.onap.aaf.misc.rosetta.env.RosettaEnv; + + +public class JettyServiceStarter extends AbsServiceStarter { + + private boolean secure; + + public JettyServiceStarter(final AbsService service) throws OrganizationException { + super(service); + secure = true; + } + + /** + * Specifically set this Service starter to Insecure (HTTP) Mode. + * @return + */ + public JettyServiceStarter insecure() { + secure = false; + return this; + } + +// @Override +// public void _propertyAdjustment() { +// Properties props = access().getProperties(); +// Object temp = null; +// // Critical - if no Security Protocols set, then set it. We'll just get messed up if not +// if((temp=props.get(Config.CADI_PROTOCOLS))==null) { +// if((temp=props.get(Config.HTTPS_PROTOCOLS))==null) { +// props.put(Config.CADI_PROTOCOLS, SecurityInfo.HTTPS_PROTOCOLS_DEFAULT); +// } else { +// props.put(Config.CADI_PROTOCOLS, temp); +// } +// } +// +// if("1.7".equals(System.getProperty("java.specification.version"))) { +// System.setProperty(Config.HTTPS_CIPHER_SUITES, Config.HTTPS_CIPHER_SUITES_DEFAULT); +// } +// System.setProperty(Config.HTTPS_CIPHER_SUITES, temp.toString()); +// } + + @Override + public void _propertyAdjustment() { +// System.setProperty("com.sun.management.jmxremote.port", "8081"); + Properties props = access().getProperties(); + Object httpproto = null; + // Critical - if no Security Protocols set, then set it. We'll just get messed up if not + if((httpproto=props.get(Config.CADI_PROTOCOLS))==null) { + if((httpproto=props.get(Config.HTTPS_PROTOCOLS))==null) { + props.put(Config.CADI_PROTOCOLS, (httpproto=SecurityInfo.HTTPS_PROTOCOLS_DEFAULT)); + } else { + props.put(Config.CADI_PROTOCOLS, httpproto); + } + } + + if("1.7".equals(System.getProperty("java.specification.version")) && (httpproto==null || (httpproto instanceof String && ((String)httpproto).contains("TLSv1.2")))) { + System.setProperty(Config.HTTPS_CIPHER_SUITES, Config.HTTPS_CIPHER_SUITES_DEFAULT); + } + } + + @Override + public void _start(RServlet rserv) throws Exception { + final String hostname = access().getProperty(Config.HOSTNAME, "localhost"); + final int port = Integer.parseInt(access().getProperty("port","0")); + final String keystore = access().getProperty(Config.CADI_KEYSTORE, null); + final int IDLE_TIMEOUT = Integer.parseInt(access().getProperty(Config.AAF_CONN_IDLE_TIMEOUT, Config.AAF_CONN_IDLE_TIMEOUT_DEF)); + Server server = new Server(); + + ServerConnector conn; + String protocol; + if(!secure || keystore==null) { + conn = new ServerConnector(server); + protocol = "http"; + } else { + protocol = "https"; + + String keystorePassword = access().getProperty(Config.CADI_KEYSTORE_PASSWORD, null); + if(keystorePassword==null) { + throw new CadiException("No Keystore Password configured for " + keystore); + } + SslContextFactory sslContextFactory = new SslContextFactory(); + sslContextFactory.setKeyStorePath(keystore); + String temp; + sslContextFactory.setKeyStorePassword(temp=access().decrypt(keystorePassword, true)); // don't allow unencrypted + sslContextFactory.setKeyManagerPassword(temp); + temp=null; // don't leave lying around + + String truststore = access().getProperty(Config.CADI_TRUSTSTORE, null); + if(truststore!=null) { + String truststorePassword = access().getProperty(Config.CADI_TRUSTSTORE_PASSWORD, null); + if(truststorePassword==null) { + throw new CadiException("No Truststore Password configured for " + truststore); + } + sslContextFactory.setTrustStorePath(truststore); + sslContextFactory.setTrustStorePassword(access().decrypt(truststorePassword, true)); + } + // Be able to accept only certain protocols, i.e. TLSv1.1+ + final String[] protocols = Split.splitTrim(',', access().getProperty(Config.CADI_PROTOCOLS, SecurityInfo.HTTPS_PROTOCOLS_DEFAULT)); + sslContextFactory.setIncludeProtocols(protocols); + + // Want to use Client Certificates, if they exist. + sslContextFactory.setWantClientAuth(true); + + // Optional future checks. + // sslContextFactory.setValidateCerts(true); + // sslContextFactory.setValidatePeerCerts(true); + // sslContextFactory.setEnableCRLDP(false); + // sslContextFactory.setEnableOCSP(false); + String certAlias = access().getProperty(Config.CADI_ALIAS, null); + if(certAlias!=null) { + sslContextFactory.setCertAlias(certAlias); + } + + HttpConfiguration httpConfig = new HttpConfiguration(); + httpConfig.setSecureScheme(protocol); + httpConfig.setSecurePort(port); + httpConfig.addCustomizer(new SecureRequestCustomizer()); + // httpConfig.setOutputBufferSize(32768); Not sure why take this setting + + conn = new ServerConnector(server, + new SslConnectionFactory(sslContextFactory,HttpVersion.HTTP_1_1.asString()), + new HttpConnectionFactory(httpConfig) + ); + } + + // Setup JMX + // TODO trying to figure out how to set up/log ports +// MBeanServer mbeanServer = ManagementFactory.getPlatformMBeanServer(); +// MBeanContainer mbContainer=new MBeanContainer(mbeanServer); +// server.addEventListener(mbContainer); +// server.addBean(mbContainer); + + // Add loggers MBean to server (will be picked up by MBeanContainer above) +// server.addBean(Log.getLog()); + + conn.setHost(hostname); + conn.setPort(port); + conn.setIdleTimeout(IDLE_TIMEOUT); + server.addConnector(conn); + + server.setHandler(new AbstractHandler() { + private FilterChain fc = buildFilterChain(service,new FilterChain() { + @Override + public void doFilter(ServletRequest req, ServletResponse resp) throws IOException, ServletException { + rserv.service(req, resp); + } + }); + + @Override + public void handle(String target, Request baseRequest, HttpServletRequest hreq, HttpServletResponse hresp) throws IOException, ServletException { + try { + fc.doFilter(hreq,hresp); + } catch (Exception e) { + service.access.log(e, "Error Processing " + target); + hresp.setStatus(500 /* Service Error */); + } + baseRequest.setHandled(true); + } + } + ); + + try { + access().printf(Level.INIT, "Starting service on %s:%d (%s)",hostname,port,InetAddress.getLocalHost().getHostAddress()); + server.start(); + access().log(Level.INIT,server.dump()); + } catch (Exception e) { + access().log(e,"Error starting " + service.app_name); + System.exit(1); + } + try { + register(service.registrants(port)); + access().printf(Level.INIT, "Starting Jetty Service for %s, version %s, on %s://%s:%d", service.app_name,service.app_version,protocol,hostname,port); + } catch(Exception e) { + access().log(e,"Error registering " + service.app_name); + // Question: Should Registered Services terminate? + } + server.join(); + } + + private FilterChain buildFilterChain(final AbsService as, final FilterChain doLast) throws CadiException, LocatorException { + Filter[] filters = as.filters(); + FilterChain fc = doLast; + for(int i=filters.length-1;i>=0;--i) { + fc = new FCImpl(filters[i],fc); + } + return fc; + } + + private class FCImpl implements FilterChain { + private Filter f; + private FilterChain next; + + public FCImpl(final Filter f, final FilterChain fc) { + this.f=f; + next = fc; + + } + @Override + public void doFilter(ServletRequest req, ServletResponse resp) throws IOException, ServletException { + f.doFilter(req,resp, next); + } + } +} diff --git a/auth/auth-core/src/main/java/org/onap/aaf/auth/server/ServiceStarter.java b/auth/auth-core/src/main/java/org/onap/aaf/auth/server/ServiceStarter.java new file mode 100644 index 00000000..529d2d35 --- /dev/null +++ b/auth/auth-core/src/main/java/org/onap/aaf/auth/server/ServiceStarter.java @@ -0,0 +1,26 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ +package org.onap.aaf.auth.server; + +public interface ServiceStarter { + public void start() throws Exception; + public void shutdown(); +} diff --git a/auth/auth-core/src/main/java/org/onap/aaf/auth/validation/Validator.java b/auth/auth-core/src/main/java/org/onap/aaf/auth/validation/Validator.java new file mode 100644 index 00000000..16c0d3ba --- /dev/null +++ b/auth/auth-core/src/main/java/org/onap/aaf/auth/validation/Validator.java @@ -0,0 +1,204 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.validation; + +import java.util.ArrayList; +import java.util.List; +import java.util.regex.Pattern; + +import org.onap.aaf.auth.layer.Result; + + +public class Validator { + private static final String ESSENTIAL = "\\x25\\x28\\x29\\x2C-\\x2E\\x30-\\x39\\x3D\\x40-\\x5A\\x5F\\x61-\\x7A"; + private static final Pattern ESSENTIAL_CHARS = Pattern.compile("["+ESSENTIAL+"]+"); + public static final Pattern ACTION_CHARS = Pattern.compile( + "["+ESSENTIAL+"]+" + // All AlphaNumeric+ + "|\\*" // Just Star + ); + public static final Pattern INST_CHARS = Pattern.compile( + "["+ESSENTIAL+"]+[\\*]*" + // All AlphaNumeric+ possibly ending with * + "|\\*" + // Just Star + "|(([:/]\\*)|([:/][!]{0,1}["+ESSENTIAL+"]+[\\*]*[:/]*))+" // Key :asdf:*:sdf*:sdk + ); + public static final Pattern ID_CHARS = Pattern.compile("[\\w.-]+@[\\w.-]+"); + public static final Pattern NAME_CHARS = Pattern.compile("[\\w.-]+"); + public static final Pattern DESC_CHAR = Pattern.compile("["+ESSENTIAL+"\\x20]+"); + public static List nsKeywords; + protected final Pattern actionChars; + protected final Pattern instChars; + private StringBuilder msgs; + + static { + nsKeywords = new ArrayList(); + nsKeywords.add(".access"); + nsKeywords.add(".owner"); + nsKeywords.add(".admin"); + nsKeywords.add(".member"); + nsKeywords.add(".perm"); + nsKeywords.add(".role"); + nsKeywords.add(".ns"); + nsKeywords.add(".cred"); + } + + public Validator() { + actionChars = ACTION_CHARS; + instChars = INST_CHARS; + } + + public final String errs() { + return msgs.toString(); + } + + public final Validator nullOrBlank(String name, String str) { + if(str==null) { + msg(name + " is null."); + } else if(str.length()==0) { + msg(name + " is blank."); + } + return this; + } + + public final Validator isNull(String name, Object o) { + if(o==null) { + msg(name + " is null."); + } + return this; + } + + protected final boolean noMatch(String str, Pattern p) { + return !p.matcher(str).matches(); + } + protected final boolean nob(String str, Pattern p) { + return str==null || !p.matcher(str).matches(); + } + + protected final void msg(String ... strs) { + if(msgs==null) { + msgs=new StringBuilder(); + } + for(String str : strs) { + msgs.append(str); + } + msgs.append('\n'); + } + + public final boolean err() { + return msgs!=null; + } + + public final Validator notOK(Result res) { + if(res==null) { + msgs.append("Result object is blank"); + } else if(res.notOK()) { + msgs.append(res.getClass().getSimpleName() + " is not OK"); + } + return this; + } + + protected Validator intRange(String text, int target, int start, int end) { + if(targetend) { + msg(text + " is out of range (" + start + '-' + end + ')'); + } + return this; + } + + protected Validator floatRange(String text, float target, float start, float end) { + if(targetend) { + msg(text + " is out of range (" + start + '-' + end + ')'); + } + return this; + } + + protected Validator description(String type, String description) { + if(description!=null) { + if(noMatch(description, DESC_CHAR)) { + msg(type + " Description is invalid."); + } + } + return this; + } + + public final Validator permType(String type) { + if(nob(type,NAME_CHARS)) { + msg("Perm Type [" +type + "] is invalid."); + } + return this; + } + + public final Validator permType(String type, String ns) { + if(nob(type,NAME_CHARS)) { + msg("Perm Type [" + (ns==null?"":ns+(type.length()==0?"":'.'))+type + "] is invalid."); + } + return this; + } + + public final Validator permInstance(String instance) { + if(nob(instance,instChars)) { + msg("Perm Instance [" + instance + "] is invalid."); + } + return this; + } + + public final Validator permAction(String action) { + // TODO check for correct Splits? Type|Instance|Action ? + if(nob(action, actionChars)) { + msg("Perm Action [" + action + "] is invalid."); + } + return this; + } + + public final Validator role(String role) { + if(nob(role, NAME_CHARS)) { + msg("Role [" + role + "] is invalid."); + } + return this; + } + + public final Validator ns(String ns) { + if(nob(ns,NAME_CHARS)){ + msg("NS [" + ns + "] is invalid."); + } + for(String s : nsKeywords) { + if(ns.endsWith(s)) { + msg("NS [" + ns + "] may not be named with NS keywords"); + break; + } + } + return this; + } + + public final Validator key(String key) { + if(nob(key,NAME_CHARS)) { + msg("NS Prop Key [" + key + "] is invalid"); + } + return this; + } + + public final Validator value(String value) { + if(nob(value,ESSENTIAL_CHARS)) { + msg("NS Prop value [" + value + "] is invalid"); + } + return this; + } + +} diff --git a/auth/auth-core/src/test/java/org/onap/aaf/auth/common/test/JU_Define.java b/auth/auth-core/src/test/java/org/onap/aaf/auth/common/test/JU_Define.java new file mode 100644 index 00000000..89e1aa94 --- /dev/null +++ b/auth/auth-core/src/test/java/org/onap/aaf/auth/common/test/JU_Define.java @@ -0,0 +1,66 @@ +/******************************************************************************* + * ============LICENSE_START==================================================== + * * org.onap.aaf + * * =========================================================================== + * * Copyright © 2017 AT&T Intellectual Property. All rights reserved. + * * =========================================================================== + * * 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==================================================== + * * + * * + ******************************************************************************/ +package org.onap.aaf.auth.common.test; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.onap.aaf.cadi.CadiException; +import org.onap.aaf.cadi.config.Config; +import org.onap.aaf.misc.env.Env; +import static org.junit.Assert.*; + +//import com.att.authz.common.Define; +import org.powermock.api.mockito.PowerMockito; +import org.powermock.modules.junit4.PowerMockRunner; + +@RunWith(PowerMockRunner.class) +//TODO: Gabe [JUnit] class path/ class Define is missing, com.att.authz.common also missing +public class JU_Define { + //Define define; + public static String ROOT_NS="NS.Not.Set"; + public static String ROOT_COMPANY=ROOT_NS; + + @Mock + Env envMock; + + +// @Before +// public void setUp(){ +// define = new Define(); +// } +// +// @Test +// public void testSet() throws CadiException { +// PowerMockito.when(envMock.getProperty(Config.AAF_ROOT_NS)).thenReturn("aaf_root_ns"); +// PowerMockito.when(envMock.getProperty(Config.AAF_ROOT_COMPANY)).thenReturn("aaf_root_company"); +// //PowerMockito.when(envMock.init().log()).thenReturn(null); +// //PowerMockito.doNothing().doThrow(new CadiException()).when(envMock).init().log(Matchers.anyString()); +// //define.set(envMock); +// } + + @Test + public void netYetTested() { + fail("Tests not yet implemented"); + } +} diff --git a/auth/auth-core/src/test/java/org/onap/aaf/auth/env/test/JU_AuthzEnv.java b/auth/auth-core/src/test/java/org/onap/aaf/auth/env/test/JU_AuthzEnv.java new file mode 100644 index 00000000..1117fce7 --- /dev/null +++ b/auth/auth-core/src/test/java/org/onap/aaf/auth/env/test/JU_AuthzEnv.java @@ -0,0 +1,174 @@ +/******************************************************************************* + * ============LICENSE_START==================================================== + * * org.onap.aaf + * * =========================================================================== + * * Copyright © 2017 AT&T Intellectual Property. All rights reserved. + * * =========================================================================== + * * 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==================================================== + * * + * * + ******************************************************************************/ +package org.onap.aaf.auth.env.test; + +import static org.junit.Assert.*; +import static org.mockito.Mockito.mock; +import java.io.IOException; +import java.io.InputStream; +import java.util.Properties; +import org.onap.aaf.cadi.Access; +import static org.mockito.Mockito.when; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.onap.aaf.auth.env.AuthzEnv; +import org.onap.aaf.cadi.PropAccess; +import org.onap.aaf.cadi.Access.Level; +import org.onap.aaf.cadi.config.Config; +import org.onap.aaf.misc.env.APIException; +import org.powermock.modules.junit4.PowerMockRunner; + +import junit.framework.Assert; + +@RunWith(PowerMockRunner.class) +public class JU_AuthzEnv { + private static final org.onap.aaf.cadi.Access.Level DEBUG = null; + AuthzEnv authzEnv; + enum Level {DEBUG, INFO, AUDIT, INIT, WARN, ERROR}; + + @Before + public void setUp(){ + PropAccess access = null; + Properties props = null; + authzEnv = new AuthzEnv(); + AuthzEnv authzEnv1 = new AuthzEnv("Test"); + AuthzEnv authzEnv2 = new AuthzEnv(props); + AuthzEnv authzEnv3 = new AuthzEnv(access); + } + + @Test + public void testTransRate() { + Long Result = authzEnv.transRate(); + System.out.println("value of result " +Result); //Expected 300000 + assertNotNull(Result); + } + + @Test + public void checkNewTransNoAvg() { + + Assert.assertNotNull(authzEnv.newTransNoAvg()); + } + + @Test + public void checkNewTrans() { + Assert.assertNotNull(authzEnv.newTrans()); + } + + @Test + public void checkPropAccess() { + Assert.assertNotNull(authzEnv.access()); + } + + @Test + public void checkgetProperties() { //TODO:[GABE]No setter for this, add? + Assert.assertNotNull(authzEnv.getProperties()); + Assert.assertNotNull(authzEnv.getProperties("test")); + } + + @Test(expected = APIException.class) + public void checkSetLog4JNames() throws APIException {//TODO: Find better way to test instead of just seeing if strings pass + authzEnv.setLog4JNames("path", "root","service","audit","init","trace"); + authzEnv.setLog4JNames("path", "root",null,"audit","init","trace"); + } + + @Test + public void checkPropertyGetters(){ + authzEnv.setProperty("key","value"); + Assert.assertEquals(authzEnv.getProperty("key"), "value"); + Assert.assertEquals(authzEnv.getProperty("key","value"), "value"); + } + + @Test + public void checkPropertySetters(){ + Assert.assertEquals(authzEnv.getProperty("key","value"), authzEnv.setProperty("key","value")); + } + + @Test(expected = IOException.class) + public void testDecryptException() throws IOException{ + String encrypted = "enc:"; + authzEnv.setProperty(Config.CADI_KEYFILE, "test");//TODO: Figure out setter for this + authzEnv.decrypt(encrypted, true); + authzEnv.decrypt("", false); + } + + @Test + public void testDecrypt() throws IOException{ + String encrypted = "encrypted"; + String Result = authzEnv.decrypt(encrypted, true); + System.out.println("value of res " +Result); + assertEquals("encrypted",Result); + } + + @Test + public void testClassLoader() { + ClassLoader cLoad = mock(ClassLoader.class); + cLoad = authzEnv.classLoader(); + Assert.assertNotNull(cLoad); + } + + @Test + public void testLoad() throws IOException { + InputStream is = mock(InputStream.class); + authzEnv.load(is); + } + + @Test + public void testLog() { + Access.Level lvl = Access.Level.DEBUG; + Object msgs = null; + authzEnv.log(lvl, msgs); + } + + @Test + public void testLog1() { + Exception e = new Exception(); + Object msgs = null; + authzEnv.log(e, msgs); + } + + @Test + public void testPrintf() { + Access.Level lvl = Access.Level.DEBUG; + Object msgs = null; + authzEnv.printf(lvl, "Test", msgs); + } + + @Test + public void testWillLog() { + Access.Level lvl = Access.Level.DEBUG; + Access.Level lvl1 = Access.Level.AUDIT; + boolean test = authzEnv.willLog(lvl); + Assert.assertFalse(test); + test = authzEnv.willLog(lvl1); + Assert.assertTrue(test); + + } + + @Test + public void testSetLogLevel() { + Access.Level lvl = Access.Level.DEBUG; + authzEnv.setLogLevel(lvl); + } + +} diff --git a/auth/auth-core/src/test/java/org/onap/aaf/auth/env/test/JU_AuthzTransFilter.java b/auth/auth-core/src/test/java/org/onap/aaf/auth/env/test/JU_AuthzTransFilter.java new file mode 100644 index 00000000..f874e9d0 --- /dev/null +++ b/auth/auth-core/src/test/java/org/onap/aaf/auth/env/test/JU_AuthzTransFilter.java @@ -0,0 +1,130 @@ +/******************************************************************************* + * ============LICENSE_START==================================================== + * * org.onap.aaf + * * =========================================================================== + * * Copyright © 2017 AT&T Intellectual Property. All rights reserved. + * * =========================================================================== + * * 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==================================================== + * * + * * + ******************************************************************************/ +package org.onap.aaf.auth.env.test; + +import static org.junit.Assert.*; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.anyInt; +import static org.mockito.Mockito.*; +import org.mockito.Mock; +import java.security.Principal; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import org.onap.aaf.auth.env.AuthzEnv; +import org.onap.aaf.auth.env.AuthzTrans; +import org.onap.aaf.auth.env.AuthzTransFilter; +import org.onap.aaf.auth.env.AuthzTransImpl; +import org.onap.aaf.cadi.CadiException; +import org.onap.aaf.cadi.Connector; +import org.onap.aaf.cadi.PropAccess; +import org.onap.aaf.cadi.TrustChecker; +import org.onap.aaf.cadi.principal.TaggedPrincipal; +import org.onap.aaf.misc.env.LogTarget; +import org.onap.aaf.misc.env.Slot; +import org.onap.aaf.misc.env.Trans.Metric; +import org.powermock.api.mockito.PowerMockito; +import org.powermock.modules.junit4.PowerMockRunner; + +@RunWith(PowerMockRunner.class) +public class JU_AuthzTransFilter { +AuthzTransFilter authzTransFilter; +AuthzEnv authzEnvMock = mock(AuthzEnv.class); +Connector connectorMock = mock(Connector.class); +TrustChecker trustCheckerMock = mock(TrustChecker.class); +AuthzTrans authzTransMock = mock(AuthzTrans.class); +Object additionalTafLurs = mock(Object.class); + + @Before + public void setUp() throws CadiException{ + when(authzEnvMock.access()).thenReturn(new PropAccess()); + //when(authzEnvMock.newTrans()).thenReturn(new AuthzTransImpl(authzEnvMock)); + authzTransFilter = new AuthzTransFilter(authzEnvMock, connectorMock, trustCheckerMock, additionalTafLurs); + + + } + +/* @Test + public void testTallyHo(){ + PowerMockito.when(authzTransMock.info().isLoggable()).thenReturn(true); + //TODO: Gabe [JUnit] Not visible for junit + //if(trans.info().isLoggable()) + //authzTransFilter.tallyHo(authzTransMock); + + }*/ + + /*@Test + public void testProtected() throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException { + Method newTransMethod = AuthzTransFilter.class.getDeclaredMethod("newTrans"); + newTransMethod.setAccessible(true); + + newTransMethod.invoke(authzTransFilter); + }*/ + + @Test + public void testAuthenticated() throws IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException, SecurityException, CadiException { + Principal p = mock(Principal.class); + AuthzTransFilter aTF = new AuthzTransFilter(authzEnvMock, connectorMock, trustCheckerMock, null); + Class c = aTF.getClass(); + Class[] cArg = new Class[2]; + cArg[0] = AuthzTrans.class; + cArg[1] = Principal.class; //Steps to test a protected method + Method authenticatedMethod = c.getDeclaredMethod("authenticated", cArg); + authenticatedMethod.setAccessible(true); + authenticatedMethod.invoke(aTF,authzTransMock, null); + } + + @Test + public void testTallyHo() throws CadiException, NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException { + Slot specialLogSlot = authzEnvMock.slot("SPECIAL_LOG_SLOT"); + LogTarget lt = mock(LogTarget.class); + AuthzTransFilter aTF = new AuthzTransFilter(authzEnvMock, connectorMock, trustCheckerMock, additionalTafLurs); + TaggedPrincipal tPrin = mock(TaggedPrincipal.class); + Metric met = new Metric(); + met.total = 199.33F; + met.entries = 15; + met.buckets = new float[] {199.33F,99.33F}; + Class c = aTF.getClass(); + Class[] cArg = new Class[1]; + cArg[0] = AuthzTrans.class; //Steps to test a protected method + Method tallyHoMethod = c.getDeclaredMethod("tallyHo", cArg); + StringBuilder sb = new StringBuilder("AuditTrail\n"); + when(authzTransMock.auditTrail(((LogTarget)any()), anyInt(),(StringBuilder)any(),anyInt(),anyInt())).thenReturn(met); + tallyHoMethod.setAccessible(true); + when(authzTransMock.get(specialLogSlot, false)).thenReturn(false); + when(authzTransMock.warn()).thenReturn(lt); + when(authzTransMock.info()).thenReturn(lt); + tallyHoMethod.invoke(aTF,authzTransMock); + when(authzTransMock.getUserPrincipal()).thenReturn(tPrin); + tallyHoMethod.invoke(aTF,authzTransMock); + + } + + + + +} diff --git a/auth/auth-core/src/test/java/org/onap/aaf/auth/env/test/JU_AuthzTransImpl.java b/auth/auth-core/src/test/java/org/onap/aaf/auth/env/test/JU_AuthzTransImpl.java new file mode 100644 index 00000000..c646e52e --- /dev/null +++ b/auth/auth-core/src/test/java/org/onap/aaf/auth/env/test/JU_AuthzTransImpl.java @@ -0,0 +1,169 @@ +/******************************************************************************* + * ============LICENSE_START==================================================== + * * org.onap.aaf + * * =========================================================================== + * * Copyright © 2017 AT&T Intellectual Property. All rights reserved. + * * =========================================================================== + * * 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==================================================== + * * + * * + ******************************************************************************/ +package org.onap.aaf.auth.env.test; + +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import java.security.Principal; +import java.util.Date; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.onap.aaf.auth.env.AuthzEnv; +import org.onap.aaf.auth.env.AuthzTransImpl; +import org.onap.aaf.auth.env.AuthzTrans.REQD_TYPE; +import org.onap.aaf.auth.org.Organization; +import org.onap.aaf.auth.org.OrganizationFactory; +import org.onap.aaf.cadi.Lur; +import org.onap.aaf.cadi.Permission; +import org.onap.aaf.misc.env.Env; +import org.onap.aaf.misc.env.LogTarget; +import org.powermock.modules.junit4.PowerMockRunner; + +import junit.framework.Assert; + +@RunWith(PowerMockRunner.class) +public class JU_AuthzTransImpl { + + AuthzTransImpl authzTransImpl; + @Mock + AuthzEnv authzEnvMock; + AuthzTransImpl trans1; + + private Organization org=null; + private AuthzTransImpl mockAuthzTransImpl; + private static HttpServletRequest req; + private static HttpServletResponse res; + private Lur lur1 = mock(Lur.class); + + @Before + public void setUp(){ + authzTransImpl = new AuthzTransImpl(authzEnvMock); + req = mock(HttpServletRequest.class); + authzTransImpl.set(req); + when(req.getParameter("request")).thenReturn("NotNull"); + authzTransImpl.set(req); + when(req.getParameter("request")).thenReturn(""); + authzTransImpl.set(req); + } + + @Test + public void testOrg() { + Organization result=null; + result = authzTransImpl.org(); + OrganizationFactory test = mock(OrganizationFactory.class); + //result = OrganizationFactory.obtain(authzTransImpl.env(), authzTransImpl.user()); + authzTransImpl.org(); + //when(test).thenReturn(null); + //assertTrue(true); + } + + @Mock + LogTarget logTargetMock; + + @Test + public void testLogAuditTrail(){ + + when(logTargetMock.isLoggable()).thenReturn(false); + authzTransImpl.logAuditTrail(logTargetMock); + when(logTargetMock.isLoggable()).thenReturn(true); + Env delegate = mock(Env.class); + //when(logTargetMock.isLoggable()).thenReturn(true);//TODO: Figure this out + //authzTransImpl.logAuditTrail(logTargetMock); + } + +// @Test //TODO:Fix this AAF-111 +// public void testSetUser() { +// Principal user = mock(Principal.class); +// authzTransImpl.setUser(user); +// Principal user1 = authzTransImpl.getUserPrincipal(); +// String username = user1.getName(); +// Assert.assertNotNull(user1); +// } + +// @Test //TODO:Fix this AAF-111 +// public void testUser() { +// Assert.assertEquals("n/a", authzTransImpl.user()); +// Principal user = mock(Principal.class); //Unsure how to modify name +// when(user.toString()).thenReturn("name"); +// when(user.getName()).thenReturn("name"); +// authzTransImpl.setUser(user); +// Assert.assertEquals("name", authzTransImpl.user()); +// } +// + @Test + public void testRequested() { + REQD_TYPE user = REQD_TYPE.move; + REQD_TYPE user1 = REQD_TYPE.future; + HttpServletRequest req = mock(HttpServletRequest.class); + String p = user1.name(); + boolean boolUser = authzTransImpl.requested(user); + Assert.assertEquals(false, boolUser); + Assert.assertNotNull(p); + authzTransImpl.requested(user,true); + when(authzTransImpl.requested(user)).thenReturn(null); + Assert.assertEquals(true, authzTransImpl.requested(user)); + /* String p1 = req.getParameter(user1.name()); //unable to access private method call in all instances + when(req.getParameter(user1.name())).thenReturn("test"); + authzTransImpl.requested(user,false); + */ + + + } + + @Test + public void testFish() { + mockAuthzTransImpl = mock(AuthzTransImpl.class); + Permission p = mock(Permission.class); + authzTransImpl.fish(p); + String str = "Test"; + lur1.createPerm(str); + when(p.match(p)).thenReturn(true); + authzTransImpl.setLur(lur1); + authzTransImpl.fish(p); + } + + @Test + public void testSetVariables() { //TODO: refactor this better + Assert.assertNull(authzTransImpl.agent()); + Assert.assertNull(authzTransImpl.ip()); + Assert.assertNull(authzTransImpl.path()); + Assert.assertNotNull(authzTransImpl.port()); + Assert.assertNull(authzTransImpl.meth()); + Assert.assertNull(authzTransImpl.getUserPrincipal()); + Assert.assertNotNull(authzTransImpl.user()); + } + + @Test + public void testNow() { + Date date = new Date(); + Assert.assertEquals(date,authzTransImpl.now()); + when(authzTransImpl.now()).thenReturn(null); + } + +} diff --git a/auth/auth-core/src/test/java/org/onap/aaf/auth/env/test/JU_AuthzTransOnlyFilter.java b/auth/auth-core/src/test/java/org/onap/aaf/auth/env/test/JU_AuthzTransOnlyFilter.java new file mode 100644 index 00000000..b29e716a --- /dev/null +++ b/auth/auth-core/src/test/java/org/onap/aaf/auth/env/test/JU_AuthzTransOnlyFilter.java @@ -0,0 +1,121 @@ +/******************************************************************************* + * ============LICENSE_START==================================================== + * * org.onap.aaf + * * =========================================================================== + * * Copyright © 2017 AT&T Intellectual Property. All rights reserved. + * * =========================================================================== + * * 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==================================================== + * * + * * + ******************************************************************************/ +package org.onap.aaf.auth.env.test; + +import static org.junit.Assert.*; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import static org.mockito.Mockito.*; +import javax.servlet.http.HttpServletRequest; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + +import javax.servlet.ServletRequest; + +import org.onap.aaf.cadi.principal.TaggedPrincipal; +import org.onap.aaf.misc.env.Env; +import org.mockito.runners.MockitoJUnitRunner; +import org.onap.aaf.auth.env.AuthzEnv; +import org.onap.aaf.auth.env.AuthzTrans; +import org.onap.aaf.auth.env.AuthzTransFilter; +import org.onap.aaf.auth.env.AuthzTransOnlyFilter; +import org.onap.aaf.cadi.CadiException; +import org.onap.aaf.cadi.Connector; +import org.onap.aaf.cadi.TrustChecker; +import org.onap.aaf.misc.env.LogTarget; +import org.onap.aaf.misc.env.Slot; +import org.onap.aaf.misc.env.Trans; +import org.onap.aaf.misc.env.Trans.Metric; + +@RunWith(MockitoJUnitRunner.class) +public class JU_AuthzTransOnlyFilter { + AuthzTransFilter authzTransFilter; + AuthzEnv authzEnvMock = mock(AuthzEnv.class); + Connector connectorMock = mock(Connector.class); + TrustChecker trustCheckerMock = mock(TrustChecker.class); + AuthzTrans authzTransMock = mock(AuthzTrans.class); + Object additionalTafLurs = mock(Object.class); + ServletRequest servletRequestMock = mock(ServletRequest.class); + AuthzTransOnlyFilter authzTransOnlyFilter; + + @Before + public void setUp(){ + authzTransOnlyFilter = new AuthzTransOnlyFilter(authzEnvMock); + } + + /*@Test + public void testProtected() throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException { + Method newTransMethod = AuthzTransFilter.class.getDeclaredMethod("newTrans"); + newTransMethod.setAccessible(true); + + newTransMethod.invoke(authzTransFilter); + }*/ + + @Test + public void testStart() throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException { + AuthzTransOnlyFilter aTF = new AuthzTransOnlyFilter(authzEnvMock); + Class c = aTF.getClass(); + Class[] cArg = new Class[2]; + cArg[0] = AuthzTrans.class; + cArg[1] = ServletRequest.class; //Steps to test a protected method + Method startMethod = c.getDeclaredMethod("start", cArg); + startMethod.setAccessible(true); + //startMethod.invoke(aTF, authzTransMock, servletRequestMock); + } + + @Test + public void testAuthenticated() throws IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException, SecurityException, CadiException { + TaggedPrincipal p = mock(TaggedPrincipal.class); + AuthzTransOnlyFilter aTF = new AuthzTransOnlyFilter(authzEnvMock); + Class c = aTF.getClass(); + Class[] cArg = new Class[2]; + cArg[0] = AuthzTrans.class; + cArg[1] = TaggedPrincipal.class; //Steps to test a protected method + Method authenticatedMethod = c.getDeclaredMethod("authenticated", cArg); + authenticatedMethod.setAccessible(true); + authenticatedMethod.invoke(aTF,authzTransMock, null); + } + + @Test + public void testTallyHo() throws CadiException, NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException { + AuthzTransOnlyFilter aTF = new AuthzTransOnlyFilter(authzEnvMock); + LogTarget log = mock(LogTarget.class); + Metric met = new Metric(); + met.total = 199.33F; + met.entries = 15; + met.buckets = new float[] {199.33F,99.33F}; + Class c = aTF.getClass(); + Class[] cArg = new Class[1]; + cArg[0] = AuthzTrans.class; //Steps to test a protected method + StringBuilder sb = new StringBuilder("AuditTrail\n"); + when(authzTransMock.auditTrail(anyInt(),(StringBuilder)any(),anyInt(),anyInt())).thenReturn(met); + when(authzTransMock.info()).thenReturn(log); + doNothing().when(log).log((StringBuilder)any()); + Method tallyHoMethod = c.getDeclaredMethod("tallyHo", cArg); + tallyHoMethod.setAccessible(true); + tallyHoMethod.invoke(aTF,authzTransMock); + } + +} diff --git a/auth/auth-core/src/test/java/org/onap/aaf/auth/env/test/JU_NullTrans.java b/auth/auth-core/src/test/java/org/onap/aaf/auth/env/test/JU_NullTrans.java new file mode 100644 index 00000000..e82aa163 --- /dev/null +++ b/auth/auth-core/src/test/java/org/onap/aaf/auth/env/test/JU_NullTrans.java @@ -0,0 +1,273 @@ +/******************************************************************************* + * ============LICENSE_START==================================================== + * * org.onap.aaf + * * =========================================================================== + * * Copyright © 2017 AT&T Intellectual Property. All rights reserved. + * * =========================================================================== + * * 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==================================================== + * * + * * + ******************************************************************************/ +package org.onap.aaf.auth.env.test; + +import static org.junit.Assert.*; + +import javax.servlet.http.HttpServletRequest; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.runners.MockitoJUnitRunner; +import org.onap.aaf.auth.env.AuthzEnv; +import org.onap.aaf.auth.env.AuthzTrans; +import org.onap.aaf.auth.env.NullTrans; +import org.onap.aaf.auth.env.AuthzTrans.REQD_TYPE; +import org.onap.aaf.auth.org.Organization; +import org.onap.aaf.cadi.Permission; +import org.onap.aaf.misc.env.Decryptor; +import org.onap.aaf.misc.env.Encryptor; +import org.onap.aaf.misc.env.LogTarget; +import org.onap.aaf.misc.env.Slot; +import org.onap.aaf.misc.env.TimeTaken; + +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import java.security.Principal; +import java.util.Date; + +@RunWith(MockitoJUnitRunner.class) +public class JU_NullTrans { + NullTrans nullTrans; + + @Before + public void setUp(){ + nullTrans = new NullTrans(); + } + + @Test + public void testAuditTrail() { + Assert.assertNull(nullTrans.auditTrail(0, null, 0)); + } + + @Test + public void testSingleton() { + AuthzTrans single = nullTrans.singleton(); + Assert.assertTrue(single instanceof AuthzTrans); + } + + @Test + public void testCheckpoints() { + nullTrans.checkpoint("Test"); + nullTrans.checkpoint(null, 0); + } + + @Test + public void testFatal() { + LogTarget log = nullTrans.fatal(); + Assert.assertEquals(LogTarget.NULL, log); + } + + @Test + public void testError() { + LogTarget log = nullTrans.error(); + Assert.assertEquals(LogTarget.NULL, log); + } + + @Test + public void testAudit() { + LogTarget log = nullTrans.audit(); + Assert.assertEquals(LogTarget.NULL, log); + } + + @Test + public void testInit() { + LogTarget log = nullTrans.init(); + Assert.assertEquals(LogTarget.NULL, log); + } + + @Test + public void testWarn() { + LogTarget log = nullTrans.warn(); + Assert.assertEquals(LogTarget.NULL, log); + } + + @Test + public void testInfo() { + LogTarget log = nullTrans.info(); + Assert.assertEquals(LogTarget.NULL, log); + } + + @Test + public void testDebug() { + LogTarget log = nullTrans.debug(); + Assert.assertEquals(LogTarget.NULL, log); + } + + @Test + public void testTrace() { + LogTarget log = nullTrans.trace(); + Assert.assertEquals(LogTarget.NULL, log); + } + + @Test + public void testStart() { + TimeTaken test = nullTrans.start("test", 1); + StringBuilder sb = new StringBuilder(); + test.output(sb); + StringBuilder sb1 = new StringBuilder(); + sb1.append(test); + String s = sb.toString(); + String s1 = sb1.toString(); + s1 = s1.trim(); + Assert.assertEquals(s,s1); + } + + @Test + public void testSetProperty() { + String tag = "tag"; + String value = "value"; + nullTrans.setProperty(tag, value); + String expected = nullTrans.getProperty(tag, value); + Assert.assertEquals(expected, value); + String expectedTag = nullTrans.getProperty(tag); + Assert.assertEquals(expectedTag, tag); + } + + @Test + public void testDecryptor() { + Decryptor decry = nullTrans.decryptor(); + Assert.assertNull(decry); + } + + @Test + public void testEncryptor() { + Encryptor encry = nullTrans.encryptor(); + Assert.assertNull(encry); + } + + @Test + public void testSet() { + HttpServletRequest req = mock(HttpServletRequest.class); + AuthzTrans set = nullTrans.set(req); + Assert.assertNull(set); + } + + @Test + public void testUser() { + String user = nullTrans.user(); + Assert.assertNull(user); + } + + @Test + public void testGetUserPrincipal() { + Principal principal = nullTrans.getUserPrincipal(); + Assert.assertNull(principal); + } + + @Test + public void testIp() { + String ip = nullTrans.ip(); + Assert.assertNull(ip); + } + + @Test + public void testMeth() { + String meth = nullTrans.meth(); + Assert.assertNull(meth); + } + + @Test + public void testPort() { + int port = nullTrans.port(); + Assert.assertEquals(port,0); + } + + @Test + public void testPath() { + String path = nullTrans.path(); + Assert.assertNull(path); + } + + @Test + public void testPut() { + nullTrans.put(null, nullTrans); + } + + @Test + public void testSetUser() { + Principal principal = mock(Principal.class); + //nullTrans.setUser(principal); + } + + @Test + public void testSlot() { + Slot slot = nullTrans.slot(null); + Assert.assertNull(slot); + } + + @Test + public void testEnv() { + AuthzEnv env = nullTrans.env(); + Assert.assertNull(env); + } + + @Test + public void testAgent() { + String agent = nullTrans.agent(); + Assert.assertNull(agent); + } + + @Test + public void testSetLur() { + nullTrans.setLur(null); + } + + @Test + public void testFish() { + Permission perm = mock(Permission.class); + Boolean fish = nullTrans.fish(perm); + Assert.assertFalse(fish); + } + + @Test + public void testOrg() { + Organization org = nullTrans.org(); + Assert.assertEquals(Organization.NULL, org); + } + + @Test + public void testLogAuditTrail() { + LogTarget lt = mock(LogTarget.class); + nullTrans.logAuditTrail(lt); + } + + @Test + public void testRequested() { + Boolean reqd = nullTrans.requested(null); + Assert.assertFalse(reqd); + nullTrans.requested(null, true); + } + + @Test + public void testNow() { + Date date = new Date(); + Assert.assertEquals(date,nullTrans.now()); + //when(nullTrans.now()).thenReturn(null); + } + + + +} diff --git a/auth/auth-core/src/test/java/org/onap/aaf/auth/layer/test/JU_Result.java b/auth/auth-core/src/test/java/org/onap/aaf/auth/layer/test/JU_Result.java new file mode 100644 index 00000000..fc812a2c --- /dev/null +++ b/auth/auth-core/src/test/java/org/onap/aaf/auth/layer/test/JU_Result.java @@ -0,0 +1,58 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ +package org.onap.aaf.auth.layer.test; + +import static org.junit.Assert.*; + +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mock; +import org.onap.aaf.auth.layer.Result; + +public class JU_Result { + Result result; +// @Mock +// RV value; + int status=0; + String details = "details"; + String[] variables; + + @SuppressWarnings({ "unchecked", "rawtypes" }) + @Before + public void setUp(){ + //TODO: Gabe [JUnit] Not visible for junit + //result = new Result(result, status, details, variables); + } + +// @Test +// public void testPartialContent() { +// Result Res = result.partialContent(true); +// System.out.println("Res" +Res); +// assertEquals(details,Res.toString()); +// +// } + + @Test + public void netYetTested() { + fail("Tests not yet implemented"); + } + +} diff --git a/auth/auth-core/src/test/java/org/onap/aaf/auth/local/test/JU_DataFile.java b/auth/auth-core/src/test/java/org/onap/aaf/auth/local/test/JU_DataFile.java new file mode 100644 index 00000000..a7ea2953 --- /dev/null +++ b/auth/auth-core/src/test/java/org/onap/aaf/auth/local/test/JU_DataFile.java @@ -0,0 +1,70 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ +package org.onap.aaf.auth.local.test; + +import java.io.File; +import java.util.ArrayList; +import java.util.List; +import static org.junit.Assert.*; +import org.junit.AfterClass; +import org.junit.Test; +import org.onap.aaf.auth.local.DataFile; +import org.onap.aaf.auth.local.DataFile.Token; +import org.onap.aaf.auth.local.DataFile.Token.Field; + +public class JU_DataFile { + + @AfterClass + public static void tearDownAfterClass() throws Exception { + } + + @Test + public void netYetTested() { + fail("Tests not yet implemented"); + } + +// @Test +// public void test() throws Exception { +// File file = new File("../authz-batch/data/v1.dat"); +// DataFile df = new DataFile(file,"r"); +// int count = 0; +// List list = new ArrayList(); +// try { +// df.open(); +// Token tok = df.new Token(1024000); +// Field fld = tok.new Field('|'); +// +// while(tok.nextLine()) { +// ++count; +// fld.reset(); +// list.add(fld.at(0)); +// } +//// Collections.sort(list); +// for(String s: list) { +// System.out.println(s); +// +// } +// } finally { +// System.out.printf("%15s:%12d\n","Total",count); +// } +// } + +} diff --git a/auth/auth-core/src/test/java/org/onap/aaf/auth/local/test/JU_TextIndex.java b/auth/auth-core/src/test/java/org/onap/aaf/auth/local/test/JU_TextIndex.java new file mode 100644 index 00000000..613d2a80 --- /dev/null +++ b/auth/auth-core/src/test/java/org/onap/aaf/auth/local/test/JU_TextIndex.java @@ -0,0 +1,76 @@ +/******************************************************************************* + * ============LICENSE_START==================================================== + * * org.onap.aaf + * * =========================================================================== + * * Copyright © 2017 AT&T Intellectual Property. All rights reserved. + * * =========================================================================== + * * 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==================================================== + * * + * * + ******************************************************************************/ +package org.onap.aaf.auth.local.test; + +import static org.junit.Assert.*; +import static org.mockito.Matchers.*; +import static org.mockito.Mockito.*; + +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStreamWriter; +import java.io.Writer; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.runners.MockitoJUnitRunner; +import org.onap.aaf.auth.local.DataFile; +import org.onap.aaf.auth.local.TextIndex; +import org.onap.aaf.misc.env.TimeTaken; +import org.onap.aaf.misc.env.Trans; + +@RunWith(MockitoJUnitRunner.class) +public class JU_TextIndex { + TextIndex textIndex; + Trans trans; + DataFile datefile; + @Mock + File file; + + @Before + public void setUp() throws IOException{ //TODO: AAF-111 fix once actual input is known. + char character = 'a'; + String filePath = "test/output_key"; + File keyfile = new File(filePath); + FileOutputStream is = new FileOutputStream(keyfile); + OutputStreamWriter osw = new OutputStreamWriter(is); + Writer w = new BufferedWriter(osw); + w.write("asdfasdfasdf"); + w.close(); + datefile = new DataFile(keyfile, "test"); + trans = mock(Trans.class); + textIndex = new TextIndex(keyfile); + //textIndex.create(trans, datefile, 20, character, 2, 2); + keyfile.delete(); + } + + @Test + public void testOpen() throws IOException { + //textIndex.open(); + } + +} diff --git a/auth/auth-core/src/test/java/org/onap/aaf/auth/org/test/JU_OrganizationException.java b/auth/auth-core/src/test/java/org/onap/aaf/auth/org/test/JU_OrganizationException.java new file mode 100644 index 00000000..01b8256f --- /dev/null +++ b/auth/auth-core/src/test/java/org/onap/aaf/auth/org/test/JU_OrganizationException.java @@ -0,0 +1,48 @@ +/******************************************************************************* + * ============LICENSE_START==================================================== + * * org.onap.aaf + * * =========================================================================== + * * Copyright © 2017 AT&T Intellectual Property. All rights reserved. + * * =========================================================================== + * * 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==================================================== + * * + * * + ******************************************************************************/ +package org.onap.aaf.auth.org.test; + +import static org.junit.Assert.*; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.onap.aaf.auth.org.OrganizationException; +import org.powermock.modules.junit4.PowerMockRunner; + +@RunWith(PowerMockRunner.class) +public class JU_OrganizationException { + + OrganizationException organizationException; + + @Before + public void setUp(){ + organizationException = new OrganizationException(); + } + + + @Test + public void test() { + assertTrue(true); + } + +} diff --git a/auth/auth-core/src/test/java/org/onap/aaf/auth/org/test/JU_OrganizationFactory.java b/auth/auth-core/src/test/java/org/onap/aaf/auth/org/test/JU_OrganizationFactory.java new file mode 100644 index 00000000..2136e786 --- /dev/null +++ b/auth/auth-core/src/test/java/org/onap/aaf/auth/org/test/JU_OrganizationFactory.java @@ -0,0 +1,64 @@ +/******************************************************************************* + * ============LICENSE_START==================================================== + * * org.onap.aaf + * * =========================================================================== + * * Copyright © 2017 AT&T Intellectual Property. All rights reserved. + * * =========================================================================== + * * 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==================================================== + * * + * * + ******************************************************************************/ +package org.onap.aaf.auth.org.test; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import static org.mockito.Mockito.mock; +import org.onap.aaf.auth.env.AuthzEnv; +import org.onap.aaf.auth.org.OrganizationException; +import org.onap.aaf.auth.org.OrganizationFactory; +import org.onap.aaf.misc.env.APIException; +import org.onap.aaf.misc.env.impl.BasicEnv; +import org.powermock.api.mockito.PowerMockito; +import org.powermock.modules.junit4.PowerMockRunner; + +@RunWith(PowerMockRunner.class) +public class JU_OrganizationFactory { + private static final String ORG_SLOT = null; + OrganizationFactory organizationFactory; + BasicEnv bEnv; + @Mock + AuthzEnv authzEnvMock; + String orgClass="orgclass"; + String orgNS="orgns"; + @Before + public void setUp(){ + organizationFactory = new OrganizationFactory(); + bEnv = new BasicEnv(); + } + + @SuppressWarnings("static-access") + @Test(expected = APIException.class) + public void testInit() throws OrganizationException { + organizationFactory.init(bEnv); + } + +// @SuppressWarnings("static-access") TODO:Fix this AAF-111 +// @Test(expected = OrganizationException.class) +// public void testObtain() throws OrganizationException{ +// PowerMockito.when(authzEnvMock.getProperty("Organization."+orgNS)).thenReturn("notnull"); +// organizationFactory.obtain(authzEnvMock, orgNS); +// } +} diff --git a/auth/auth-core/src/test/java/org/onap/aaf/auth/request/test/CredCompare.java b/auth/auth-core/src/test/java/org/onap/aaf/auth/request/test/CredCompare.java new file mode 100644 index 00000000..cac26a88 --- /dev/null +++ b/auth/auth-core/src/test/java/org/onap/aaf/auth/request/test/CredCompare.java @@ -0,0 +1,64 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.request.test; + +import static junit.framework.Assert.*; + +import java.util.GregorianCalendar; + +import org.onap.aaf.misc.env.util.Chrono; + +import aaf.v2_0.CredRequest; + +public class CredCompare extends RosettaCompare { + public CredCompare() { + super(CredRequest.class); + } + + public static CredRequest create() { + CredRequest rr = new CredRequest(); + String in = instance(); + rr.setId("m888"+ in + "@ns.att.com"); + rr.setPassword("Bogus0"+in); + rr.setType(200); + GregorianCalendar gc = new GregorianCalendar(); + rr.setStart(Chrono.timeStamp(gc)); + gc.add(GregorianCalendar.MONTH, 1); + rr.setEnd(Chrono.timeStamp(gc)); + return rr; + } + + @Override + public void compare(CredRequest t1, CredRequest t2) { + assertEquals(t1.getId(),t2.getId()); + assertEquals(t1.getPassword(),t2.getPassword()); + assertEquals(t1.getType(),t2.getType()); + assertEquals(t1.getStart(),t2.getStart()); + assertEquals(t1.getEnd(),t2.getEnd()); + } + + + @Override + public CredRequest newOne() { + return create(); + } +} \ No newline at end of file diff --git a/auth/auth-core/src/test/java/org/onap/aaf/auth/request/test/JU_RequestCheck.java b/auth/auth-core/src/test/java/org/onap/aaf/auth/request/test/JU_RequestCheck.java new file mode 100644 index 00000000..38bd51fc --- /dev/null +++ b/auth/auth-core/src/test/java/org/onap/aaf/auth/request/test/JU_RequestCheck.java @@ -0,0 +1,42 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.request.test; + +import org.junit.Test; +import org.onap.aaf.misc.env.APIException; +import org.onap.aaf.misc.rosetta.env.RosettaEnv; + +public class JU_RequestCheck { + + @Test + public void testNSRequest() throws APIException { + RosettaEnv env = new RosettaEnv(); + new NSCompare().run(env); + new NSAttribCompare().run(env); + new RoleCompare().run(env); + new PermCompare().run(env); + new CredCompare().run(env); + new UserRoleCompare().run(env); + new RolePermCompare().run(env); + new MultiCompare().run(env); + }; +} diff --git a/auth/auth-core/src/test/java/org/onap/aaf/auth/request/test/MultiCompare.java b/auth/auth-core/src/test/java/org/onap/aaf/auth/request/test/MultiCompare.java new file mode 100644 index 00000000..5450bf55 --- /dev/null +++ b/auth/auth-core/src/test/java/org/onap/aaf/auth/request/test/MultiCompare.java @@ -0,0 +1,69 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.request.test; + +import static junit.framework.Assert.assertEquals; + +import java.util.GregorianCalendar; + +import org.onap.aaf.misc.env.util.Chrono; + +import aaf.v2_0.MultiRequest; + +public class MultiCompare extends RosettaCompare { + public MultiCompare() { + super(MultiRequest.class); + } + + @Override + public MultiRequest newOne() { + MultiRequest multi = new MultiRequest(); + multi.setNsRequest(NSCompare.create()); + multi.getNsAttribRequest().add(NSAttribCompare.create()); + multi.getNsAttribRequest().add(NSAttribCompare.create()); + multi.getRoleRequest().add(RoleCompare.create()); + multi.getRoleRequest().add(RoleCompare.create()); + multi.getPermRequest().add(PermCompare.create()); + multi.getPermRequest().add(PermCompare.create()); + multi.getCredRequest().add(CredCompare.create()); + multi.getCredRequest().add(CredCompare.create()); + multi.getUserRoleRequest().add(UserRoleCompare.create()); + multi.getUserRoleRequest().add(UserRoleCompare.create()); + multi.getRolePermRequest().add(RolePermCompare.create()); + multi.getRolePermRequest().add(RolePermCompare.create()); + + + GregorianCalendar gc = new GregorianCalendar(); + multi.setStart(Chrono.timeStamp(gc)); + gc.add(GregorianCalendar.MONTH, 1); + multi.setEnd(Chrono.timeStamp(gc)); + return multi; + } + + public void compare(MultiRequest t1, MultiRequest t2) { + new NSCompare().compare(t1.getNsRequest(), t2.getNsRequest()); + // Will have to find by key for others. + + assertEquals(t1.getStart(),t2.getStart()); + assertEquals(t1.getEnd(),t2.getEnd()); + } +} \ No newline at end of file diff --git a/auth/auth-core/src/test/java/org/onap/aaf/auth/request/test/NSAttribCompare.java b/auth/auth-core/src/test/java/org/onap/aaf/auth/request/test/NSAttribCompare.java new file mode 100644 index 00000000..9f6ce21e --- /dev/null +++ b/auth/auth-core/src/test/java/org/onap/aaf/auth/request/test/NSAttribCompare.java @@ -0,0 +1,93 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.request.test; + +import static junit.framework.Assert.assertEquals; +import static junit.framework.Assert.assertTrue; + +import java.util.GregorianCalendar; + +import org.onap.aaf.misc.env.util.Chrono; + +import aaf.v2_0.NsAttribRequest; +import aaf.v2_0.NsAttribRequest.Attrib; + +public class NSAttribCompare extends RosettaCompare { + public NSAttribCompare() { + super(NsAttribRequest.class); + } + + public static NsAttribRequest create() { + NsAttribRequest nar = new NsAttribRequest(); + String in = instance(); + + nar.setNs("org.osaaf.ns"+in); + Attrib attrib = new Attrib(); + attrib.setKey("swm"); + attrib.setValue("v"+instance()); + nar.getAttrib().add(attrib); + attrib = new Attrib(); + attrib.setKey("scamp"); + attrib.setValue("v"+instance()); + nar.getAttrib().add(attrib); + GregorianCalendar gc = new GregorianCalendar(); + nar.setStart(Chrono.timeStamp(gc)); + gc.add(GregorianCalendar.MONTH, 1); + nar.setEnd(Chrono.timeStamp(gc)); + return nar; + } + + @Override + public void compare(NsAttribRequest t1, NsAttribRequest t2) { + assertEquals(t1.getNs(),t2.getNs()); + for(Attrib a1 : t1.getAttrib()) { + boolean ok = false; + for(Attrib a2 : t2.getAttrib()) { + if(a1.getKey().equals(a2.getKey()) && + a1.getValue().equals(a2.getValue())) { + ok = true; + break; + } + } + assertTrue("a2 Attribs in a1",ok); + } + for(Attrib a2 : t2.getAttrib()) { + boolean ok = false; + for(Attrib a1 : t1.getAttrib()) { + if(a1.getKey().equals(a2.getKey()) && + a1.getValue().equals(a2.getValue())) { + ok = true; + break; + } + } + assertTrue("a2 Attribs in a1",ok); + } + assertEquals(t1.getStart(),t2.getStart()); + assertEquals(t1.getEnd(),t2.getEnd()); + } + + + @Override + public NsAttribRequest newOne() { + return create(); + } +} \ No newline at end of file diff --git a/auth/auth-core/src/test/java/org/onap/aaf/auth/request/test/NSCompare.java b/auth/auth-core/src/test/java/org/onap/aaf/auth/request/test/NSCompare.java new file mode 100644 index 00000000..b7fc28cc --- /dev/null +++ b/auth/auth-core/src/test/java/org/onap/aaf/auth/request/test/NSCompare.java @@ -0,0 +1,75 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.request.test; + +import static junit.framework.Assert.assertEquals; +import static junit.framework.Assert.assertTrue; + +import java.util.GregorianCalendar; + +import org.onap.aaf.misc.env.util.Chrono; + +import aaf.v2_0.NsRequest; + +public class NSCompare extends RosettaCompare { + public NSCompare() { + super(NsRequest.class); + } + + public static NsRequest create() { + NsRequest nsr = new NsRequest(); + String in = instance(); + nsr.setName("org.osaaf.ns"+in); + nsr.setDescription("Hello World"+in); + nsr.getAdmin().add("Fred"+in); + nsr.getAdmin().add("Barney"+in); + nsr.getResponsible().add("Wilma"+in); + nsr.getResponsible().add("Betty"+in); + nsr.setType("Hello"+in); + GregorianCalendar gc = new GregorianCalendar(); + nsr.setStart(Chrono.timeStamp(gc)); + gc.add(GregorianCalendar.MONTH, 1); + nsr.setEnd(Chrono.timeStamp(gc)); + return nsr; + } + + @Override + public void compare(NsRequest t1, NsRequest t2) { + assertEquals(t1.getName(),t2.getName()); + assertEquals(t1.getDescription(),t2.getDescription()); + for(String s : t1.getAdmin()) { + assertTrue(t2.getAdmin().contains(s)); + } + for(String s : t2.getAdmin()) { + assertTrue(t1.getAdmin().contains(s)); + } + assertEquals(t1.getType(),t2.getType()); + assertEquals(t1.getStart(),t2.getStart()); + assertEquals(t1.getEnd(),t2.getEnd()); + } + + + @Override + public NsRequest newOne() { + return create(); + } +} \ No newline at end of file diff --git a/auth/auth-core/src/test/java/org/onap/aaf/auth/request/test/PermCompare.java b/auth/auth-core/src/test/java/org/onap/aaf/auth/request/test/PermCompare.java new file mode 100644 index 00000000..3d9a9fdb --- /dev/null +++ b/auth/auth-core/src/test/java/org/onap/aaf/auth/request/test/PermCompare.java @@ -0,0 +1,66 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.request.test; + +import static junit.framework.Assert.*; + +import java.util.GregorianCalendar; + +import org.onap.aaf.misc.env.util.Chrono; + +import aaf.v2_0.PermRequest; + +public class PermCompare extends RosettaCompare { + public PermCompare() { + super(PermRequest.class); + } + + public static PermRequest create() { + PermRequest pr = new PermRequest(); + String in = instance(); + pr.setType("org.osaaf.ns.perm"+in); + pr.setInstance("instance"+in); + pr.setAction("read"); + pr.setDescription("Hello World, Perm"+in); + GregorianCalendar gc = new GregorianCalendar(); + pr.setStart(Chrono.timeStamp(gc)); + gc.add(GregorianCalendar.MONTH, 1); + pr.setEnd(Chrono.timeStamp(gc)); + return pr; + } + + @Override + public void compare(PermRequest t1, PermRequest t2) { + assertEquals(t1.getType(),t2.getType()); + assertEquals(t1.getInstance(),t2.getInstance()); + assertEquals(t1.getAction(),t2.getAction()); + assertEquals(t1.getDescription(),t2.getDescription()); + assertEquals(t1.getStart(),t2.getStart()); + assertEquals(t1.getEnd(),t2.getEnd()); + } + + + @Override + public PermRequest newOne() { + return create(); + } +} \ No newline at end of file diff --git a/auth/auth-core/src/test/java/org/onap/aaf/auth/request/test/RoleCompare.java b/auth/auth-core/src/test/java/org/onap/aaf/auth/request/test/RoleCompare.java new file mode 100644 index 00000000..35bd3370 --- /dev/null +++ b/auth/auth-core/src/test/java/org/onap/aaf/auth/request/test/RoleCompare.java @@ -0,0 +1,62 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.request.test; + +import static junit.framework.Assert.*; + +import java.util.GregorianCalendar; + +import org.onap.aaf.misc.env.util.Chrono; + +import aaf.v2_0.RoleRequest; + +public class RoleCompare extends RosettaCompare { + public RoleCompare() { + super(RoleRequest.class); + } + + public static RoleRequest create() { + RoleRequest rr = new RoleRequest(); + String in = instance(); + rr.setName("org.osaaf.ns.role"+in); + rr.setDescription("Hello World, Role"+in); + GregorianCalendar gc = new GregorianCalendar(); + rr.setStart(Chrono.timeStamp(gc)); + gc.add(GregorianCalendar.MONTH, 1); + rr.setEnd(Chrono.timeStamp(gc)); + return rr; + } + + @Override + public void compare(RoleRequest t1, RoleRequest t2) { + assertEquals(t1.getName(),t2.getName()); + assertEquals(t1.getDescription(),t2.getDescription()); + assertEquals(t1.getStart(),t2.getStart()); + assertEquals(t1.getEnd(),t2.getEnd()); + } + + + @Override + public RoleRequest newOne() { + return create(); + } +} \ No newline at end of file diff --git a/auth/auth-core/src/test/java/org/onap/aaf/auth/request/test/RolePermCompare.java b/auth/auth-core/src/test/java/org/onap/aaf/auth/request/test/RolePermCompare.java new file mode 100644 index 00000000..d6ea98b9 --- /dev/null +++ b/auth/auth-core/src/test/java/org/onap/aaf/auth/request/test/RolePermCompare.java @@ -0,0 +1,69 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.request.test; + +import static junit.framework.Assert.assertEquals; + +import java.util.GregorianCalendar; + +import org.onap.aaf.misc.env.util.Chrono; + +import aaf.v2_0.Pkey; +import aaf.v2_0.RolePermRequest; + +public class RolePermCompare extends RosettaCompare { + public RolePermCompare() { + super(RolePermRequest.class); + } + + public static RolePermRequest create() { + RolePermRequest urr = new RolePermRequest(); + String in = instance(); + urr.setRole("org.osaaf.ns.role"+in); + Pkey pkey = new Pkey(); + pkey.setType("org.osaaf.ns.myType"+in); + pkey.setInstance("myInstance"+in); + pkey.setAction("myAction"+in); + urr.setPerm(pkey); + GregorianCalendar gc = new GregorianCalendar(); + urr.setStart(Chrono.timeStamp(gc)); + gc.add(GregorianCalendar.MONTH, 1); + urr.setEnd(Chrono.timeStamp(gc)); + return urr; + } + + @Override + public void compare(RolePermRequest t1, RolePermRequest t2) { + assertEquals(t1.getRole(),t2.getRole()); + assertEquals(t1.getPerm().getType(),t1.getPerm().getType()); + assertEquals(t1.getPerm().getInstance(),t1.getPerm().getInstance()); + assertEquals(t1.getPerm().getAction(),t1.getPerm().getAction()); + assertEquals(t1.getStart(),t2.getStart()); + assertEquals(t1.getEnd(),t2.getEnd()); + } + + + @Override + public RolePermRequest newOne() { + return create(); + } +} \ No newline at end of file diff --git a/auth/auth-core/src/test/java/org/onap/aaf/auth/request/test/RosettaCompare.java b/auth/auth-core/src/test/java/org/onap/aaf/auth/request/test/RosettaCompare.java new file mode 100644 index 00000000..5130f8cb --- /dev/null +++ b/auth/auth-core/src/test/java/org/onap/aaf/auth/request/test/RosettaCompare.java @@ -0,0 +1,66 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.request.test; + +import org.onap.aaf.misc.env.APIException; +import org.onap.aaf.misc.env.Data; +import org.onap.aaf.misc.env.Data.TYPE; +import org.onap.aaf.misc.rosetta.env.RosettaDF; +import org.onap.aaf.misc.rosetta.env.RosettaData; +import org.onap.aaf.misc.rosetta.env.RosettaEnv; + +public abstract class RosettaCompare { + protected Class cls; + private static int count = 0; + + public RosettaCompare(Class cls) { + this.cls = cls; + } + + public void run(RosettaEnv env) throws APIException { + RosettaDF nsrDF = env.newDataFactory(cls); + compare(nsrDF.newData().option(Data.PRETTY),newOne(),this); + } + + private void compare(RosettaData rdt, T t, RosettaCompare comp) throws APIException { + System.out.println("########### Testing " + cls.getName() + " ##############"); + String s = rdt.load(t).out(TYPE.JSON).asString(); + System.out.println(s); + T t2 = rdt.in(TYPE.JSON).load(s).asObject(); + comp.compare(t, t2); + + System.out.println(); + + s = rdt.load(t).out(TYPE.XML).asString(); + System.out.println(s); + t2 = rdt.in(TYPE.XML).load(s).asObject(); + comp.compare(t, t2); + } + + public synchronized static String instance() { + return "_"+ ++count; + } + + public abstract void compare(T t1, T t2); + public abstract T newOne(); + +} \ No newline at end of file diff --git a/auth/auth-core/src/test/java/org/onap/aaf/auth/request/test/UserRoleCompare.java b/auth/auth-core/src/test/java/org/onap/aaf/auth/request/test/UserRoleCompare.java new file mode 100644 index 00000000..542ddeb7 --- /dev/null +++ b/auth/auth-core/src/test/java/org/onap/aaf/auth/request/test/UserRoleCompare.java @@ -0,0 +1,62 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.request.test; + +import static junit.framework.Assert.*; + +import java.util.GregorianCalendar; + +import org.onap.aaf.misc.env.util.Chrono; + +import aaf.v2_0.UserRoleRequest; + +public class UserRoleCompare extends RosettaCompare { + public UserRoleCompare() { + super(UserRoleRequest.class); + } + + public static UserRoleRequest create() { + UserRoleRequest urr = new UserRoleRequest(); + String in = instance(); + urr.setUser("m125"+in + "@ns.att.com"); + urr.setRole("org.osaaf.ns.role"+in); + GregorianCalendar gc = new GregorianCalendar(); + urr.setStart(Chrono.timeStamp(gc)); + gc.add(GregorianCalendar.MONTH, 1); + urr.setEnd(Chrono.timeStamp(gc)); + return urr; + } + + @Override + public void compare(UserRoleRequest t1, UserRoleRequest t2) { + assertEquals(t1.getUser(),t2.getUser()); + assertEquals(t1.getRole(),t2.getRole()); + assertEquals(t1.getStart(),t2.getStart()); + assertEquals(t1.getEnd(),t2.getEnd()); + } + + + @Override + public UserRoleRequest newOne() { + return create(); + } +} \ No newline at end of file diff --git a/auth/auth-core/src/test/java/org/onap/aaf/auth/rserv/test/JU_BetterMatch.java b/auth/auth-core/src/test/java/org/onap/aaf/auth/rserv/test/JU_BetterMatch.java new file mode 100644 index 00000000..af1d289e --- /dev/null +++ b/auth/auth-core/src/test/java/org/onap/aaf/auth/rserv/test/JU_BetterMatch.java @@ -0,0 +1,173 @@ +/******************************************************************************* + * ============LICENSE_START==================================================== + * * org.onap.aaf + * * =========================================================================== + * * Copyright © 2017 AT&T Intellectual Property. All rights reserved. + * * =========================================================================== + * * 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==================================================== + * * + * * + ******************************************************************************/ +package org.onap.aaf.auth.rserv.test; + +import static junit.framework.Assert.assertEquals; +import static junit.framework.Assert.assertFalse; +import static junit.framework.Assert.assertTrue; + +import java.util.Set; + +import org.junit.Assert; +import org.junit.Test; +import org.onap.aaf.auth.rserv.Match; +import org.onap.aaf.misc.env.Env; +import org.onap.aaf.misc.env.TimeTaken; +import org.onap.aaf.misc.env.Trans; +import org.onap.aaf.misc.env.impl.EnvFactory; + + +public class JU_BetterMatch { + + @Test + public void test() { + Trans trans = EnvFactory.newTrans(); + // Bad Match + Match bm = new Match("/req/1.0.0/:var"); + + assertTrue(bm.match("/req/1.0.0/fred")); + assertTrue(bm.match("/req/1.0.0/wilma")); + assertTrue(bm.match("/req/1.0.0/wilma/")); + assertFalse(bm.match("/req/1.0.0/wilma/bambam")); + assertFalse(bm.match("/not/valid/234")); + assertFalse(bm.match("")); + + TimeTaken tt = trans.start("A", Env.SUB); + TimeTaken tt2; + int i = 0; + try { + bm = new Match(null); + tt2 = trans.start(Integer.toString(++i), Env.SUB); + assertTrue(bm.match("")); + tt2.done(); + tt2 = trans.start(Integer.toString(++i), Env.SUB); + assertTrue(bm.match(null)); + tt2.done(); + } finally { + tt.done(); + } + + + tt = trans.start("B", Env.SUB); + i = 0; + try { + bm = new Match("/req/1.0.0/:urn/:ref"); + tt2 = trans.start(Integer.toString(++i), Env.SUB); + assertTrue(bm.match("/req/1.0.0/urn:fsdb,1.0,req,newreq/0x12345")); + tt2.done(); + tt2 = trans.start(Integer.toString(++i), Env.SUB); + assertFalse(bm.match("/req/1.0.0/urn")); + tt2.done(); + tt2 = trans.start(Integer.toString(++i), Env.SUB); + assertTrue(bm.match("/req/1.0.0/urn:fsdb,1.0,req,newreq/0x12345/")); + tt2.done(); + tt2 = trans.start(Integer.toString(++i), Env.SUB); + assertFalse(bm.match("/req/1.0.0/urn:fsdb,1.0,req,newreq/0x12345/x")); + tt2.done(); + tt2 = trans.start(Integer.toString(++i), Env.SUB); + assertFalse(bm.match("/req/1.0.0/urn:fsdb,1.0,req,newreq/0x12345/xyx")); + } finally { + tt2.done(); + tt.done(); + } + + tt = trans.start("C", Env.SUB); + i = 0; + try { + String url = "/req/1.0.0/"; + bm = new Match(url+":urn*"); + tt2 = trans.start(Integer.toString(++i), Env.SUB); + String value = "urn:fsdb,1.0,req,newreq/0x12345"; + + assertTrue(bm.match(url+value)); + assertEquals("urn:fsdb,1.0,req,newreq/0x12345",bm.param(url+value, ":urn")); + } finally { + tt2.done(); + tt.done(); + } + + tt = trans.start("D", Env.SUB); + i = 0; + try { + bm = new Match("/req/1.0.0/:urn/:ref*"); + tt2 = trans.start(Integer.toString(++i), Env.SUB); + assertTrue(bm.match("/req/1.0.0/urn:fsdb,1.0,req,newreq/0x12345")); + tt2.done(); + tt2 = trans.start(Integer.toString(++i), Env.SUB); + assertFalse(bm.match("/req/1.0.0/urn:fsdb,1.0,req,newreq/")); + } finally { + tt2.done(); + tt.done(); + } + + tt = trans.start("E", Env.SUB); + i = 0; + try { + bm = new Match("this*"); + tt2 = trans.start(Integer.toString(++i), Env.SUB); + assertTrue(bm.match("this")); + tt2.done(); + tt2 = trans.start(Integer.toString(++i), Env.SUB); + assertTrue(bm.match("thisandthat")); + tt2.done(); + tt2 = trans.start(Integer.toString(++i), Env.SUB); + assertTrue(bm.match("this/1.0.0/urn:fsdb,1.0,req,newreq/0x12345/")); + } finally { + tt2.done(); + tt.done(); + } + + tt = trans.start("F", Env.SUB); + i = 0; + try { + bm = new Match("*"); + tt2 = trans.start(Integer.toString(++i), Env.SUB); + assertTrue(bm.match("/this")); + } finally { + tt2.done(); + tt.done(); + } + + StringBuilder sb = new StringBuilder(); + trans.auditTrail(0, sb); + System.out.println(sb); + + } + + @Test + public void specialTest() { + Match match = new Match("/sample"); + assertTrue(match.match("/sample")); + + match = new Match("/lpeer//lpeer/:key/:item*"); + assertTrue(match.match("/lpeer//lpeer/x/y")); + assertFalse(match.match("/lpeer/x/lpeer/x/y")); + + } + + @Test + public void testGetParamNames() { + Match bm = new Match("/req/1.0.0/:var"); + Set s = bm.getParamNames(); + Assert.assertNotNull(s); + } +} diff --git a/auth/auth-core/src/test/java/org/onap/aaf/auth/rserv/test/JU_BetterMatch1.java b/auth/auth-core/src/test/java/org/onap/aaf/auth/rserv/test/JU_BetterMatch1.java new file mode 100644 index 00000000..e104009a --- /dev/null +++ b/auth/auth-core/src/test/java/org/onap/aaf/auth/rserv/test/JU_BetterMatch1.java @@ -0,0 +1,164 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.rserv.test; + +import static junit.framework.Assert.assertEquals; +import static junit.framework.Assert.assertFalse; +import static junit.framework.Assert.assertTrue; + +import org.junit.Test; +import org.onap.aaf.auth.rserv.Match; +import org.onap.aaf.misc.env.Env; +import org.onap.aaf.misc.env.TimeTaken; +import org.onap.aaf.misc.env.Trans; +import org.onap.aaf.misc.env.impl.EnvFactory; + + +public class JU_BetterMatch1 { + + @Test + public void test() { + Trans trans = EnvFactory.newTrans(); + // Bad Match + Match bm = new Match("/req/1.0.0/:var"); + + assertTrue(bm.match("/req/1.0.0/fred")); + assertTrue(bm.match("/req/1.0.0/wilma")); + assertTrue(bm.match("/req/1.0.0/wilma/")); + assertFalse(bm.match("/req/1.0.0/wilma/bambam")); + assertFalse(bm.match("/not/valid/234")); + assertFalse(bm.match("")); + + TimeTaken tt = trans.start("A", Env.SUB); + TimeTaken tt2; + int i = 0; + try { + bm = new Match(null); + tt2 = trans.start(Integer.toString(++i), Env.SUB); + assertTrue(bm.match("")); + tt2.done(); + tt2 = trans.start(Integer.toString(++i), Env.SUB); + assertTrue(bm.match(null)); + tt2.done(); + } finally { + tt.done(); + } + + + tt = trans.start("B", Env.SUB); + i = 0; + try { + bm = new Match("/req/1.0.0/:urn/:ref"); + tt2 = trans.start(Integer.toString(++i), Env.SUB); + assertTrue(bm.match("/req/1.0.0/urn:fsdb,1.0,req,newreq/0x12345")); + tt2.done(); + tt2 = trans.start(Integer.toString(++i), Env.SUB); + assertFalse(bm.match("/req/1.0.0/urn")); + tt2.done(); + tt2 = trans.start(Integer.toString(++i), Env.SUB); + assertTrue(bm.match("/req/1.0.0/urn:fsdb,1.0,req,newreq/0x12345/")); + tt2.done(); + tt2 = trans.start(Integer.toString(++i), Env.SUB); + assertFalse(bm.match("/req/1.0.0/urn:fsdb,1.0,req,newreq/0x12345/x")); + tt2.done(); + tt2 = trans.start(Integer.toString(++i), Env.SUB); + assertFalse(bm.match("/req/1.0.0/urn:fsdb,1.0,req,newreq/0x12345/xyx")); + } finally { + tt2.done(); + tt.done(); + } + + tt = trans.start("C", Env.SUB); + i = 0; + try { + String url = "/req/1.0.0/"; + bm = new Match(url+":urn*"); + tt2 = trans.start(Integer.toString(++i), Env.SUB); + String value = "urn:fsdb,1.0,req,newreq/0x12345"; + + assertTrue(bm.match(url+value)); + assertEquals("urn:fsdb,1.0,req,newreq/0x12345",bm.param(url+value, ":urn")); + } finally { + tt2.done(); + tt.done(); + } + + tt = trans.start("D", Env.SUB); + i = 0; + try { + bm = new Match("/req/1.0.0/:urn/:ref*"); + tt2 = trans.start(Integer.toString(++i), Env.SUB); + assertTrue(bm.match("/req/1.0.0/urn:fsdb,1.0,req,newreq/0x12345")); + tt2.done(); + tt2 = trans.start(Integer.toString(++i), Env.SUB); + assertFalse(bm.match("/req/1.0.0/urn:fsdb,1.0,req,newreq/")); + } finally { + tt2.done(); + tt.done(); + } + + tt = trans.start("E", Env.SUB); + i = 0; + try { + bm = new Match("this*"); + tt2 = trans.start(Integer.toString(++i), Env.SUB); + assertTrue(bm.match("this")); + tt2.done(); + tt2 = trans.start(Integer.toString(++i), Env.SUB); + assertTrue(bm.match("thisandthat")); + tt2.done(); + tt2 = trans.start(Integer.toString(++i), Env.SUB); + assertTrue(bm.match("this/1.0.0/urn:fsdb,1.0,req,newreq/0x12345/")); + } finally { + tt2.done(); + tt.done(); + } + + tt = trans.start("F", Env.SUB); + i = 0; + try { + bm = new Match("*"); + tt2 = trans.start(Integer.toString(++i), Env.SUB); + assertTrue(bm.match("whatever/this")); + } finally { + tt2.done(); + tt.done(); + } + + StringBuilder sb = new StringBuilder(); + trans.auditTrail(0, sb); + System.out.println(sb); + + } + + @Test + public void specialTest() { + Match match = new Match("/sample"); + assertTrue(match.match("/sample")); + + match = new Match("/lpeer//lpeer/:key/:item*"); + assertTrue(match.match("/lpeer//lpeer/x/y")); + assertFalse(match.match("/lpeer/x/lpeer/x/y")); + + } + +} diff --git a/auth/auth-core/src/test/java/org/onap/aaf/auth/rserv/test/JU_BetterRoute.java b/auth/auth-core/src/test/java/org/onap/aaf/auth/rserv/test/JU_BetterRoute.java new file mode 100644 index 00000000..d98cf5ce --- /dev/null +++ b/auth/auth-core/src/test/java/org/onap/aaf/auth/rserv/test/JU_BetterRoute.java @@ -0,0 +1,33 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.rserv.test; + +import org.junit.Test; + +public class JU_BetterRoute { + + @Test + public void test() { + + } + +} diff --git a/auth/auth-core/src/test/java/org/onap/aaf/auth/rserv/test/JU_CachingFileAccess.java b/auth/auth-core/src/test/java/org/onap/aaf/auth/rserv/test/JU_CachingFileAccess.java new file mode 100644 index 00000000..26e9717f --- /dev/null +++ b/auth/auth-core/src/test/java/org/onap/aaf/auth/rserv/test/JU_CachingFileAccess.java @@ -0,0 +1,184 @@ +/******************************************************************************* + * ============LICENSE_START==================================================== + * * org.onap.aaf + * * =========================================================================== + * * Copyright © 2017 AT&T Intellectual Property. All rights reserved. + * * =========================================================================== + * * 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==================================================== + * * + * * + ******************************************************************************/ +package org.onap.aaf.auth.rserv.test; + +import static org.junit.Assert.*; +import static org.mockito.Matchers.any; +import static org.mockito.Mockito.*; +import static org.mockito.Matchers.*; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.RandomAccessFile; +import java.lang.reflect.Field; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.util.NavigableMap; +import java.util.concurrent.ConcurrentSkipListMap; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.mockito.Mock; +import org.mockito.invocation.InvocationOnMock; +import org.mockito.stubbing.Answer; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.onap.aaf.auth.rserv.CachingFileAccess; +import org.onap.aaf.auth.rserv.HttpCode; +import org.onap.aaf.auth.rserv.Match; + +//import org.onap.aaf.auth.rserv.CachingFileAccess.Content; +import java.util.NavigableMap; +import org.onap.aaf.misc.env.EnvJAXB; +import org.onap.aaf.misc.env.LogTarget; +import org.onap.aaf.misc.env.StaticSlot; +import org.onap.aaf.misc.env.Store; +import org.onap.aaf.misc.env.Trans; +import org.powermock.modules.junit4.PowerMockRunner; + +import junit.framework.Assert; + + +@RunWith(PowerMockRunner.class) +public class JU_CachingFileAccess { + CachingFileAccess cachingFileAccess; + HttpCode httpCode; + EnvJAXB envJ; + Trans trans; + + + @Before + public void setUp() throws IOException{ + trans = mock(Trans.class); + HttpCode hCode = mock(HttpCode.class); + envJ = mock(EnvJAXB.class); + LogTarget log = mock(LogTarget.class); + Long lng = (long) 1234134; + when(envJ.get(envJ.staticSlot("aaf_cfa_cache_check_interval"),600000L)).thenReturn(lng); + when(envJ.get(envJ.staticSlot("aaf_cfa_max_size"), 512000)).thenReturn(512000); + when(envJ.get(envJ.staticSlot("aaf_cfa_web_path"))).thenReturn("TEST"); + when(envJ.getProperty("aaf_cfa_clear_command",null)).thenReturn("null"); + when(envJ.init()).thenReturn(log); + doNothing().when(log).log((String)any()); + cachingFileAccess = new CachingFileAccess(envJ,"test"); + + + + } + + @Test + public void testSetEnv() { + Store store = mock(Store.class); + Store store1 = mock(Store.class); + Store store2 = mock(Store.class); + String test[] = {"aaf_cfa_web_path","aaf_cfa_cache_check_interval","aaf_cfa_max_size"}; + String test1[] = {"aaf_cfa_cache_check_interval"}; + String test2[] = {"aaf_cfa_max_size"}; + cachingFileAccess.setEnv(store, test); + cachingFileAccess.setEnv(store1, test1); //These don't reach all the branches for some reason + cachingFileAccess.setEnv(store2, test2); + } + + @Test + public void testHandle() throws IOException, NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException { + HttpServletRequest req = mock(HttpServletRequest.class); + Trans trans = mock(Trans.class); + HttpServletResponse resp = mock(HttpServletResponse.class); + when(req.getPathInfo()).thenReturn("path/to/file"); + + Field matchField = HttpCode.class.getDeclaredField("match"); + matchField.setAccessible(true); + Match match = mock(Match.class); + when(match.param(anyString(), anyString())).thenReturn("null/"); + matchField.set(cachingFileAccess, match); + cachingFileAccess.handle(trans, req, resp); + when(match.param(anyString(), anyString())).thenReturn("clear"); + cachingFileAccess.handle(trans, req, resp); + } + + @Test + public void testWebPath() { + EnvJAXB envJ = mock(EnvJAXB.class); + String web_path_test = "TEST"; + Assert.assertEquals(web_path_test, cachingFileAccess.webPath()); + } + + @Test + public void testCleanupParams() { + NavigableMap content = new ConcurrentSkipListMap(); + cachingFileAccess.cleanupParams(50, 500); //TODO: find right input + } + + @Test + public void testLoad() throws IOException { + cachingFileAccess.load(null, null, "1220227200L/1220227200L", null, 1320227200L ); + String filePath = "test/output_key"; + File keyfile = new File(filePath); + RandomAccessFile randFile = new RandomAccessFile (keyfile,"rw"); + + String dPath = "test/"; + File directoryPath = new File(dPath); + directoryPath.mkdir(); + cachingFileAccess.load(null, dPath, "-", null, -1); + randFile.setLength(1024 * 1024 * 8); + cachingFileAccess.load(null, filePath, "-", null, -1); + keyfile.delete(); + directoryPath.delete(); + String filePath1 = "test/output_key"; + File keyfile1 = new File(filePath1); + keyfile1.createNewFile(); + cachingFileAccess.load(null, filePath1, "-", "test", -1); + keyfile1.delete(); + } + + @Test + public void testLoadOrDefault() throws IOException, NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException, ClassNotFoundException, InstantiationException { + String filePath = "test/output_key"; + File keyfile = new File(filePath); + cachingFileAccess.loadOrDefault(trans, filePath, "-", null, null); + keyfile.delete(); + + Trans trans = mock(Trans.class); + + String filePath1 = "test/output_key.txt"; + //File keyfile1 = new File(filePath1); + doAnswer(new Answer() { + public Void answer(InvocationOnMock invocation) throws FileNotFoundException { + throw new FileNotFoundException(); + } + }).when(trans).info(); + //cachingFileAccess.loadOrDefault(trans, "bs", "also bs", "test", null); //TODO: Needs more testing AAF-111 + //keyfile1.delete(); + } + + @Test + public void testInvalidate() { + //NavigableMap content = new ConcurrentSkipListMap(); + //Content con = mock(Content.class); + //content.put("hello", con); + cachingFileAccess.invalidate("hello"); + } + +} diff --git a/auth/auth-core/src/test/java/org/onap/aaf/auth/rserv/test/JU_CodeSetter.java b/auth/auth-core/src/test/java/org/onap/aaf/auth/rserv/test/JU_CodeSetter.java new file mode 100644 index 00000000..75d1df8f --- /dev/null +++ b/auth/auth-core/src/test/java/org/onap/aaf/auth/rserv/test/JU_CodeSetter.java @@ -0,0 +1,73 @@ +/******************************************************************************* + * ============LICENSE_START==================================================== + * * org.onap.aaf + * * =========================================================================== + * * Copyright © 2017 AT&T Intellectual Property. All rights reserved. + * * =========================================================================== + * * 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==================================================== + * * + * * + ******************************************************************************/ +package org.onap.aaf.auth.rserv.test; + +import static org.junit.Assert.*; + +import java.io.IOException; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +//import org.onap.aaf.auth.rserv.CodeSetter; +import org.onap.aaf.auth.rserv.Route; +import org.onap.aaf.misc.env.Trans; +import org.powermock.modules.junit4.PowerMockRunner; + +@RunWith(PowerMockRunner.class) +public class JU_CodeSetter { + //TODO: Gabe [JUnit] Not visible for junit + //CodeSetter codeSetter; + @Mock + Trans transMock; + @Mock + HttpServletRequest reqMock; + @Mock + HttpServletResponse respMock; + +// @Before //TODO: Fix this AAF-111 +// public void setUp(){ +// codeSetter = new CodeSetter(transMock, reqMock, respMock); +// } +// +// @SuppressWarnings("rawtypes") +// @Mock +// Route routeMock; +// +// @Test +// public void testMatches() throws IOException, ServletException{ +// boolean result = codeSetter.matches(routeMock); +// System.out.println("value of res " + codeSetter.matches(routeMock)); +// assertFalse(result); +// } + + @Test + public void netYetTested() { + fail("Tests not yet implemented"); + } + +} diff --git a/auth/auth-core/src/test/java/org/onap/aaf/auth/rserv/test/JU_Content.java b/auth/auth-core/src/test/java/org/onap/aaf/auth/rserv/test/JU_Content.java new file mode 100644 index 00000000..c2be2eb1 --- /dev/null +++ b/auth/auth-core/src/test/java/org/onap/aaf/auth/rserv/test/JU_Content.java @@ -0,0 +1,661 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.rserv.test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; + +import java.io.IOException; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.junit.Test; +import org.onap.aaf.auth.rserv.HttpCode; +import org.onap.aaf.auth.rserv.TypedCode; +import org.onap.aaf.misc.env.TransJAXB; +import org.onap.aaf.misc.env.impl.EnvFactory; + + +/** + * Test the functioning of the "Content" class, which holds, and routes to the right code based on Accept values + */ +public class JU_Content { + + + @Test + public void test() throws Exception { + final String BOOL = "Boolean"; + final String XML = "XML"; + TransJAXB trans = EnvFactory.newTrans(); + try { + HttpCode cBool = new HttpCode(BOOL,"Standard String") { + @Override + public void handle(TransJAXB trans, HttpServletRequest req, HttpServletResponse resp) { + try { + resp.getOutputStream().write(context.getBytes()); + } catch (IOException e) { + } + } + }; + + HttpCode cXML = new HttpCode(XML, "Standard String") { + @Override + public void handle(TransJAXB trans, HttpServletRequest req, HttpServletResponse resp) { + try { + resp.getOutputStream().write(context.getBytes()); + } catch (IOException e) { + } + } + }; + + TypedCode ct = new TypedCode() + .add(cBool,"application/" + Boolean.class.getName()+"+xml;charset=utf8;version=1.1") + .add(cXML,"application/xml;q=.9"); + String expected = "application/java.lang.Boolean+xml;charset=utf8;version=1.1,application/xml;q=0.9"; + assertEquals(expected,ct.toString()); + + //BogusReq req = new BogusReq(); + //expected = (expected); + //HttpServletResponse resp = new BogusResp(); + + assertNotNull("Same Content String and Accept String",ct.prep(trans,expected)); + + //expects Null (not run) + // A Boolean xml that must have charset utf8 and match version 1.2 or greater + expected = ("application/java.lang.Boolean+xml;charset=utf8;version=1.2"); + assertNull("Accept Minor Version greater than Content Minor Version",ct.prep(trans,expected)); + + // Same with (too many) spaces + expected = (" application/java.lang.Boolean+xml ; charset = utf8 ; version = 1.2 "); + assertNull("Accept Minor Version greater than Content Minor Version",ct.prep(trans,expected)); + + //expects Null (not run) + expected = ("application/java.lang.Boolean+xml;charset=utf8;version=2.1"); + assertNull("Major Versions not the same",ct.prep(trans,expected)); + + expected = ("application/java.lang.Boolean+xml;charset=utf8;version=1.0"); + assertNotNull("Content Minor Version is greater than Accept Minor Version",ct.prep(trans,expected)); + + expected = "application/java.lang.Squid+xml;charset=utf8;version=1.0,application/xml;q=.9"; + assertNotNull("2nd one will have to do...",ct.prep(trans,expected)); + + expected = "application/java.lang.Boolean+xml;charset=UTF8;version=1.0"; + assertNotNull("Minor Charset in Caps acceptable",ct.prep(trans,expected)); + + // expects no run + expected="application/java.lang.Boolean+xml;charset=MyType;version=1.0"; + assertNull("Unknown Minor Charset",ct.prep(trans,expected)); + + expected=""; + assertNotNull("Blank Acceptance",ct.prep(trans,expected)); + + expected=null; + assertNotNull("Null Acceptance",ct.prep(trans,expected)); + + expected = ("text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"); + assertNotNull("Matches application/xml, and other content not known",ct.prep(trans,expected)); + + // No SemiColon + expected = ("i/am/bogus,application/xml"); + assertNotNull("Match second entry, with no Semis",ct.prep(trans,expected)); + + } finally { + StringBuilder sb = new StringBuilder(); + trans.auditTrail(0, sb); + System.out.println(sb); + } + } +// +// Original API used HTTPServletRequest and HTTPServletResponse. Due to the fact that sometimes we use Accept, and others Content-TYpe +// I changed it to simply accept a string +// +// Jonathan 3/8/2013 +// +// @SuppressWarnings("rawtypes") +// class BogusReq implements HttpServletRequest { +// private String accept; +// +// public void accept(String accept) { +// this.accept = accept; +// } +// +// @Override +// public Object getAttribute(String name) { +// return accept; +// } +// +// +// @Override +// public Enumeration getAttributeNames() { +// return null; +// } +// +// @Override +// public String getCharacterEncoding() { +// return null; +// } +// +// @Override +// public void setCharacterEncoding(String env) +// throws UnsupportedEncodingException { +// +// +// } +// +// @Override +// public int getContentLength() { +// +// return 0; +// } +// +// @Override +// public String getContentType() { +// +// return null; +// } +// +// @Override +// public ServletInputStream getInputStream() throws IOException { +// +// return null; +// } +// +// @Override +// public String getParameter(String name) { +// +// return null; +// } +// +// @Override +// public Enumeration getParameterNames() { +// +// return null; +// } +// +// @Override +// public String[] getParameterValues(String name) { +// +// return null; +// } +// +// @Override +// public Map getParameterMap() { +// +// return null; +// } +// +// @Override +// public String getProtocol() { +// +// return null; +// } +// +// @Override +// public String getScheme() { +// +// return null; +// } +// +// @Override +// public String getServerName() { +// +// return null; +// } +// +// @Override +// public int getServerPort() { +// +// return 0; +// } +// +// @Override +// public BufferedReader getReader() throws IOException { +// +// return null; +// } +// +// @Override +// public String getRemoteAddr() { +// +// return null; +// } +// +// @Override +// public String getRemoteHost() { +// +// return null; +// } +// +// @Override +// public void setAttribute(String name, Object o) { +// +// +// } +// +// @Override +// public void removeAttribute(String name) { +// +// +// } +// +// @Override +// public Locale getLocale() { +// +// return null; +// } +// +// @Override +// public Enumeration getLocales() { +// +// return null; +// } +// +// @Override +// public boolean isSecure() { +// +// return false; +// } +// +// @Override +// public RequestDispatcher getRequestDispatcher(String path) { +// +// return null; +// } +// +// @Override +// public String getRealPath(String path) { +// +// return null; +// } +// +// @Override +// public int getRemotePort() { +// +// return 0; +// } +// +// @Override +// public String getLocalName() { +// +// return null; +// } +// +// @Override +// public String getLocalAddr() { +// +// return null; +// } +// +// @Override +// public int getLocalPort() { +// +// return 0; +// } +// +// @Override +// public String getAuthType() { +// +// return null; +// } +// +// @Override +// public Cookie[] getCookies() { +// +// return null; +// } +// +// @Override +// public long getDateHeader(String name) { +// +// return 0; +// } +// +// @Override +// public String getHeader(String name) { +// return accept; +// } +// +// @Override +// public Enumeration getHeaders(String name) { +// +// return null; +// } +// +// @Override +// public Enumeration getHeaderNames() { +// +// return null; +// } +// +// @Override +// public int getIntHeader(String name) { +// +// return 0; +// } +// +// @Override +// public String getMethod() { +// +// return null; +// } +// +// @Override +// public String getPathInfo() { +// +// return null; +// } +// +// @Override +// public String getPathTranslated() { +// +// return null; +// } +// +// @Override +// public String getContextPath() { +// +// return null; +// } +// +// @Override +// public String getQueryString() { +// +// return null; +// } +// +// @Override +// public String getRemoteUser() { +// +// return null; +// } +// +// @Override +// public boolean isUserInRole(String role) { +// +// return false; +// } +// +// @Override +// public Principal getUserPrincipal() { +// +// return null; +// } +// +// @Override +// public String getRequestedSessionId() { +// +// return null; +// } +// +// @Override +// public String getRequestURI() { +// +// return null; +// } +// +// @Override +// public StringBuffer getRequestURL() { +// +// return null; +// } +// +// @Override +// public String getServletPath() { +// +// return null; +// } +// +// @Override +// public HttpSession getSession(boolean create) { +// +// return null; +// } +// +// @Override +// public HttpSession getSession() { +// +// return null; +// } +// +// @Override +// public boolean isRequestedSessionIdValid() { +// +// return false; +// } +// +// @Override +// public boolean isRequestedSessionIdFromCookie() { +// +// return false; +// } +// +// @Override +// public boolean isRequestedSessionIdFromURL() { +// +// return false; +// } +// +// @Override +// public boolean isRequestedSessionIdFromUrl() { +// +// return false; +// } +// } +// +// public class BogusResp implements HttpServletResponse { +// public String contentType; +// +// @Override +// public String getCharacterEncoding() { +// +// return null; +// } +// +// @Override +// public String getContentType() { +// return contentType; +// } +// +// @Override +// public ServletOutputStream getOutputStream() throws IOException { +// +// return null; +// } +// +// @Override +// public PrintWriter getWriter() throws IOException { +// +// return null; +// } +// +// @Override +// public void setCharacterEncoding(String charset) { +// +// +// } +// +// @Override +// public void setContentLength(int len) { +// +// +// } +// +// @Override +// public void setContentType(String type) { +// contentType = type; +// } +// +// @Override +// public void setBufferSize(int size) { +// +// +// } +// +// @Override +// public int getBufferSize() { +// +// return 0; +// } +// +// @Override +// public void flushBuffer() throws IOException { +// +// +// } +// +// @Override +// public void resetBuffer() { +// +// +// } +// +// @Override +// public boolean isCommitted() { +// +// return false; +// } +// +// @Override +// public void reset() { +// +// +// } +// +// @Override +// public void setLocale(Locale loc) { +// +// +// } +// +// @Override +// public Locale getLocale() { +// +// return null; +// } +// +// @Override +// public void addCookie(Cookie cookie) { +// +// +// } +// +// @Override +// public boolean containsHeader(String name) { +// +// return false; +// } +// +// @Override +// public String encodeURL(String url) { +// +// return null; +// } +// +// @Override +// public String encodeRedirectURL(String url) { +// +// return null; +// } +// +// @Override +// public String encodeUrl(String url) { +// +// return null; +// } +// +// @Override +// public String encodeRedirectUrl(String url) { +// +// return null; +// } +// +// @Override +// public void sendError(int sc, String msg) throws IOException { +// +// +// } +// +// @Override +// public void sendError(int sc) throws IOException { +// +// +// } +// +// @Override +// public void sendRedirect(String location) throws IOException { +// +// +// } +// +// @Override +// public void setDateHeader(String name, long date) { +// +// +// } +// +// @Override +// public void addDateHeader(String name, long date) { +// +// +// } +// +// @Override +// public void setHeader(String name, String value) { +// +// +// } +// +// @Override +// public void addHeader(String name, String value) { +// +// +// } +// +// @Override +// public void setIntHeader(String name, int value) { +// +// +// } +// +// @Override +// public void addIntHeader(String name, int value) { +// +// +// } +// +// @Override +// public void setStatus(int sc) { +// +// +// } +// +// @Override +// public void setStatus(int sc, String sm) { +// +// +// } +// +// } +// +} diff --git a/auth/auth-core/src/test/java/org/onap/aaf/auth/rserv/test/JU_Content1.java b/auth/auth-core/src/test/java/org/onap/aaf/auth/rserv/test/JU_Content1.java new file mode 100644 index 00000000..4d640d09 --- /dev/null +++ b/auth/auth-core/src/test/java/org/onap/aaf/auth/rserv/test/JU_Content1.java @@ -0,0 +1,130 @@ +/******************************************************************************* + * ============LICENSE_START==================================================== + * * org.onap.aaf + * * =========================================================================== + * * Copyright © 2017 AT&T Intellectual Property. All rights reserved. + * * =========================================================================== + * * 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==================================================== + * * + * * + ******************************************************************************/ +package org.onap.aaf.auth.rserv.test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; + +import java.io.IOException; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.junit.Test; +import org.onap.aaf.auth.rserv.HttpCode; +import org.onap.aaf.auth.rserv.TypedCode; +import org.onap.aaf.misc.env.TransJAXB; +import org.onap.aaf.misc.env.impl.EnvFactory; + + +/** + * Test the functioning of the "Content" class, which holds, and routes to the right code based on Accept values + */ +public class JU_Content1 { + + + @Test + public void test() throws Exception { + final String BOOL = "Boolean"; + final String XML = "XML"; + TransJAXB trans = EnvFactory.newTrans(); + try { + HttpCode cBool = new HttpCode(BOOL,"Standard String") { + @Override + public void handle(TransJAXB trans, HttpServletRequest req, HttpServletResponse resp) { + try { + resp.getOutputStream().write(context.getBytes()); + } catch (IOException e) { + } + } + }; + + HttpCode cXML = new HttpCode(XML, "Standard String") { + @Override + public void handle(TransJAXB trans, HttpServletRequest req, HttpServletResponse resp) { + try { + resp.getOutputStream().write(context.getBytes()); + } catch (IOException e) { + } + } + }; + + TypedCode ct = new TypedCode() + .add(cBool,"application/" + Boolean.class.getName()+"+xml;charset=utf8;version=1.1") + .add(cXML,"application/xml;q=.9"); + String expected = "application/java.lang.Boolean+xml;charset=utf8;version=1.1,application/xml;q=0.9"; + assertEquals(expected,ct.toString()); + + //BogusReq req = new BogusReq(); + //expected = (expected); + //HttpServletResponse resp = new BogusResp(); + + assertNotNull("Same Content String and Accept String",ct.prep(trans,expected)); + + //expects Null (not run) + // A Boolean xml that must have charset utf8 and match version 1.2 or greater + expected = ("application/java.lang.Boolean+xml;charset=utf8;version=1.2"); + assertNull("Accept Minor Version greater than Content Minor Version",ct.prep(trans,expected)); + + // Same with (too many) spaces + expected = (" application/java.lang.Boolean+xml ; charset = utf8 ; version = 1.2 "); + assertNull("Accept Minor Version greater than Content Minor Version",ct.prep(trans,expected)); + + //expects Null (not run) + expected = ("application/java.lang.Boolean+xml;charset=utf8;version=2.1"); + assertNull("Major Versions not the same",ct.prep(trans,expected)); + + expected = ("application/java.lang.Boolean+xml;charset=utf8;version=1.0"); + assertNotNull("Content Minor Version is greater than Accept Minor Version",ct.prep(trans,expected)); + + expected = "application/java.lang.Squid+xml;charset=utf8;version=1.0,application/xml;q=.9"; + assertNotNull("2nd one will have to do...",ct.prep(trans,expected)); + + expected = "application/java.lang.Boolean+xml;charset=UTF8;version=1.0"; + assertNotNull("Minor Charset in Caps acceptable",ct.prep(trans,expected)); + + // expects no run + expected="application/java.lang.Boolean+xml;charset=MyType;version=1.0"; + assertNull("Unknown Minor Charset",ct.prep(trans,expected)); + + expected=""; + assertNotNull("Blank Acceptance",ct.prep(trans,expected)); + + expected=null; + assertNotNull("Null Acceptance",ct.prep(trans,expected)); + + expected = ("text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"); + assertNotNull("Matches application/xml, and other content not known",ct.prep(trans,expected)); + + // No SemiColon + expected = ("i/am/bogus,application/xml"); + assertNotNull("Match second entry, with no Semis",ct.prep(trans,expected)); + + } finally { + StringBuilder sb = new StringBuilder(); + trans.auditTrail(0, sb); + System.out.println(sb); + } + } + +} diff --git a/auth/auth-core/src/test/java/org/onap/aaf/auth/rserv/test/JU_Pair.java b/auth/auth-core/src/test/java/org/onap/aaf/auth/rserv/test/JU_Pair.java new file mode 100644 index 00000000..557c7ec5 --- /dev/null +++ b/auth/auth-core/src/test/java/org/onap/aaf/auth/rserv/test/JU_Pair.java @@ -0,0 +1,47 @@ +/******************************************************************************* + * ============LICENSE_START==================================================== + * * org.onap.aaf + * * =========================================================================== + * * Copyright © 2017 AT&T Intellectual Property. All rights reserved. + * * =========================================================================== + * * 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==================================================== + * * + * * + ******************************************************************************/ +package org.onap.aaf.auth.rserv.test; + +import static org.junit.Assert.*; + +import org.junit.Before; +import org.junit.Test; +import org.onap.aaf.auth.rserv.Pair; + +import junit.framework.Assert; + +public class JU_Pair { + Pair pair; + Integer x; + Integer y; + + @Before + public void setUp(){ + pair = new Pair(1, 2); + } + + @Test + public void testToString() { + String result = pair.toString(); + Assert.assertEquals("X: " + pair.x.toString() + "-->" + pair.y.toString(), result); + } +} diff --git a/auth/auth-core/src/test/java/org/onap/aaf/auth/rserv/test/JU_Route.java b/auth/auth-core/src/test/java/org/onap/aaf/auth/rserv/test/JU_Route.java new file mode 100644 index 00000000..d5953b10 --- /dev/null +++ b/auth/auth-core/src/test/java/org/onap/aaf/auth/rserv/test/JU_Route.java @@ -0,0 +1,38 @@ +package org.onap.aaf.auth.rserv.test; + +import static org.junit.Assert.*; +import org.junit.Before; +import static org.mockito.Matchers.*; +import static org.mockito.Mockito.*; +import org.junit.Test; +import org.mockito.Matchers; +import org.onap.aaf.auth.rserv.Route; +import org.onap.aaf.misc.env.Trans; +import org.onap.aaf.auth.rserv.*; + +public class JU_Route { + Route route; + HttpCode httpCode; + HttpMethods httpMethod; + Trans trans; + + @Before + public void setUp() { //TODO: AAF-111 complete when actual input is provided + //httpMethod = Matchers.any(HttpMethods.class); + //when(httpMethod.name()).thenReturn("test"); + // route = new Route(null,"path/to/place"); + } + + + @Test + public void testAdd() { + // route.add(httpCode, "path/to/place"); + } + + @Test + public void testStart() { + // trans = mock(Trans.class); + // route.start(trans, "test", httpCode, "test"); + } + +} diff --git a/auth/auth-core/src/test/java/org/onap/aaf/auth/rserv/test/JU_RouteReport.java b/auth/auth-core/src/test/java/org/onap/aaf/auth/rserv/test/JU_RouteReport.java new file mode 100644 index 00000000..a9fdff60 --- /dev/null +++ b/auth/auth-core/src/test/java/org/onap/aaf/auth/rserv/test/JU_RouteReport.java @@ -0,0 +1,40 @@ +/******************************************************************************* + * ============LICENSE_START==================================================== + * * org.onap.aaf + * * =========================================================================== + * * Copyright © 2017 AT&T Intellectual Property. All rights reserved. + * * =========================================================================== + * * 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==================================================== + * * + * * + ******************************************************************************/ +package org.onap.aaf.auth.rserv.test; + +import static org.junit.Assert.*; +import org.onap.aaf.auth.rserv.RouteReport; + +import junit.framework.Assert; + +import org.junit.Test; + +public class JU_RouteReport { + + @Test + public void test() { + RouteReport report; + report = new RouteReport(); + Assert.assertNotNull(report); + } + +} diff --git a/auth/auth-core/src/test/java/org/onap/aaf/auth/rserv/test/JU_Routes.java b/auth/auth-core/src/test/java/org/onap/aaf/auth/rserv/test/JU_Routes.java new file mode 100644 index 00000000..2ed08841 --- /dev/null +++ b/auth/auth-core/src/test/java/org/onap/aaf/auth/rserv/test/JU_Routes.java @@ -0,0 +1,72 @@ +/******************************************************************************* + * ============LICENSE_START==================================================== + * * org.onap.aaf + * * =========================================================================== + * * Copyright © 2017 AT&T Intellectual Property. All rights reserved. + * * =========================================================================== + * * 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==================================================== + * * + * * + ******************************************************************************/ +package org.onap.aaf.auth.rserv.test; + +import static org.junit.Assert.*; + +import java.io.IOException; +import java.util.List; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import static org.mockito.Mockito.*; +//import org.onap.aaf.auth.rserv.CodeSetter; +import org.onap.aaf.auth.rserv.Route; +import org.onap.aaf.auth.rserv.Routes; +import org.onap.aaf.misc.env.Trans; +import org.powermock.modules.junit4.PowerMockRunner; + +@RunWith(PowerMockRunner.class) +public class JU_Routes { + Routes routes; + @Mock + HttpServletRequest reqMock; + //TODO: Gabe [JUnit] Not visible to junit + //CodeSetter codeSetterMock; + Route routeObj; + + @Before + public void setUp(){ + routes = new Routes(); + } + + @Test + public void testRouteReport(){ + List listVal = routes.routeReport(); + assertNotNull(listVal); + } + + @Test + public void testDerive() throws IOException, ServletException{ + routeObj = routes.derive(reqMock, null); + + } + + + + +} diff --git a/auth/auth-core/src/test/java/org/onap/aaf/auth/rserv/test/JU_TypedCode.java b/auth/auth-core/src/test/java/org/onap/aaf/auth/rserv/test/JU_TypedCode.java new file mode 100644 index 00000000..d5b57de0 --- /dev/null +++ b/auth/auth-core/src/test/java/org/onap/aaf/auth/rserv/test/JU_TypedCode.java @@ -0,0 +1,106 @@ +/******************************************************************************* + * ============LICENSE_START==================================================== + * * org.onap.aaf + * * =========================================================================== + * * Copyright © 2017 AT&T Intellectual Property. All rights reserved. + * * =========================================================================== + * * 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==================================================== + * * + * * + ******************************************************************************/ +package org.onap.aaf.auth.rserv.test; + +import static org.junit.Assert.*; + +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; +import static org.mockito.Matchers.anyString; + +import java.io.IOException; + +import javax.servlet.ServletException; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +//import org.onap.aaf.auth.rserv.Acceptor; +import org.onap.aaf.auth.rserv.HttpCode; +import org.onap.aaf.auth.rserv.HttpMethods; +import org.onap.aaf.auth.rserv.RouteReport; +import org.onap.aaf.auth.rserv.TypedCode; +import org.onap.aaf.misc.env.TimeTaken; +import org.onap.aaf.misc.env.Trans; +import org.powermock.modules.junit4.PowerMockRunner; + +@RunWith(PowerMockRunner.class) +public class JU_TypedCode { + TypedCode typedCode; + @Mock + RouteReport routeReportMock; + + @Before + public void setUp(){ + typedCode = new TypedCode(); + } + + @Test + public void testFirst(){ + String returnVal = typedCode.first(); + assertNull(returnVal); + } + + @Test + public void testAdd() { + HttpCode code = mock(HttpCode.class); + typedCode.add(code , "test", "test1", "test2"); + } + + @Test + public void testPrep() throws IOException, ServletException, ClassNotFoundException { + Trans trans = mock(Trans.class); + TimeTaken time = new TimeTaken("yell", 2) { + @Override + public void output(StringBuilder sb) { + // TODO Auto-generated method stub + } + }; + when(trans.start(";na=me;,prop", 8)).thenReturn(time); + HttpCode code = mock(HttpCode.class); + code.pathParam(null, null); + code.isAuthorized(null); //Testing httpcode, currently not working + code.no_cache(); + code.toString(); + + typedCode.add(code , ""); + typedCode.prep(null , "q"); + + typedCode.add(code , "t"); + typedCode.prep(trans , null); + + typedCode.add(code , "t"); + typedCode.prep(trans , ""); + + typedCode.add(code, "POST /authn/validate application/CredRequest+json;charset=utf-8;version=2.0,application/json;version=2.0,*/*"); + //typedCode.prep(trans , "POST /authn/validate application/CredRequest+json;charset=utf-8;version=2.0,application/json;version=2.0,*/*"); + } + + @Test + public void testRelatedTo() { + HttpCode code = mock(HttpCode.class); + StringBuilder sb = new StringBuilder(); + typedCode.relatedTo(code, sb); + } + +} diff --git a/auth/auth-core/src/test/java/org/onap/aaf/auth/rserv/test/JU_Version.java b/auth/auth-core/src/test/java/org/onap/aaf/auth/rserv/test/JU_Version.java new file mode 100644 index 00000000..617fa259 --- /dev/null +++ b/auth/auth-core/src/test/java/org/onap/aaf/auth/rserv/test/JU_Version.java @@ -0,0 +1,70 @@ +/******************************************************************************* + * ============LICENSE_START==================================================== + * * org.onap.aaf + * * =========================================================================== + * * Copyright © 2017 AT&T Intellectual Property. All rights reserved. + * * =========================================================================== + * * 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==================================================== + * * + * * + ******************************************************************************/ +package org.onap.aaf.auth.rserv.test; + +import static org.junit.Assert.*; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Matchers; +import org.mockito.Mock; +import org.onap.aaf.auth.rserv.Version; +import org.powermock.modules.junit4.PowerMockRunner; + +@RunWith(PowerMockRunner.class) +public class JU_Version { + Version version; + Version versionTest; + + + @Before + public void setUp(){ + version = new Version("first\\.123"); + versionTest = new Version("first\\.124"); + } + + @Test + public void testEquals(){ + version.equals(versionTest); + versionTest.equals(version); + versionTest = new Version("fail\\.124"); + version.equals(versionTest); + version.equals("This is not an object of version"); + versionTest = new Version("NoVersion\\.number"); + version.equals(versionTest); + + + } + + @Test + public void testToString(){ + String strVal = version.toString(); + assertNotNull(strVal); + } + + @Test + public void testHashCode() { + Assert.assertNotNull(version.hashCode()); + } +} diff --git a/auth/auth-core/src/test/java/org/onap/aaf/auth/server/test/JU_JettyServiceStarter.java b/auth/auth-core/src/test/java/org/onap/aaf/auth/server/test/JU_JettyServiceStarter.java new file mode 100644 index 00000000..463d558d --- /dev/null +++ b/auth/auth-core/src/test/java/org/onap/aaf/auth/server/test/JU_JettyServiceStarter.java @@ -0,0 +1,95 @@ +/******************************************************************************* + * ============LICENSE_START==================================================== + * * org.onap.aaf + * * =========================================================================== + * * Copyright © 2017 AT&T Intellectual Property. All rights reserved. + * * =========================================================================== + * * 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==================================================== + * * + * * + ******************************************************************************/ +package org.onap.aaf.auth.server.test; + +import static org.junit.Assert.*; + +import org.onap.aaf.auth.env.AuthzEnv; +import org.onap.aaf.auth.env.AuthzTrans; +import org.onap.aaf.auth.org.OrganizationException; +import org.onap.aaf.auth.server.AbsService; +import org.onap.aaf.auth.server.JettyServiceStarter; +import org.onap.aaf.cadi.Access; +import org.onap.aaf.cadi.CadiException; +import org.onap.aaf.cadi.LocatorException; +import org.onap.aaf.cadi.PropAccess; +import org.onap.aaf.cadi.register.Registrant; +import org.onap.aaf.misc.env.Trans; +import org.onap.aaf.misc.env.impl.BasicEnv; +import org.onap.aaf.misc.rosetta.env.RosettaEnv; +import org.junit.Test; + +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import javax.servlet.Filter; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; + +public class JU_JettyServiceStarter { + private PropAccess propAccess = new PropAccess(); + private JettyServiceStarter jss; + class TestService extends AbsService{ + + public TestService(Access access, BasicEnv env) throws CadiException { + super(access, env); + // TODO Auto-generated constructor stub + } + + @Override + public Filter[] filters() throws CadiException, LocatorException { + // TODO Auto-generated method stub + return null; + } + + @Override + public Registrant[] registrants(int port) throws CadiException, LocatorException { + // TODO Auto-generated method stub + return null; + } + + } + @SuppressWarnings("unchecked") + @Before + public void setUp() throws OrganizationException, CadiException { + Access access = mock(Access.class); + + BasicEnv bEnv = mock(BasicEnv.class); + Trans trans = mock(Trans.class); //TODO: Fix this once Gabe has services running to see correct output without mock + //TestService testService = new TestService(access, bEnv); + //jss = new JettyServiceStarter(testService); + } + + @Test + public void netYetTested() { + fail("Tests not yet implemented"); + } + + @Test + public void testPropertyAdjustment() { + //jss._propertyAdjustment(); + } + +} diff --git a/auth/auth-core/src/test/java/org/onap/aaf/auth/util/test/JU_Mask.java b/auth/auth-core/src/test/java/org/onap/aaf/auth/util/test/JU_Mask.java new file mode 100644 index 00000000..535664bd --- /dev/null +++ b/auth/auth-core/src/test/java/org/onap/aaf/auth/util/test/JU_Mask.java @@ -0,0 +1,71 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.util.test; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import java.net.InetAddress; + +import org.junit.Test; +import org.onap.aaf.cadi.util.MaskFormatException; +import org.onap.aaf.cadi.util.NetMask; + +import junit.framework.Assert; + +public class JU_Mask { + + @Test + public void test() throws Exception { + InetAddress ia = InetAddress.getLocalHost(); + NetMask mask = new NetMask(ia.getAddress()); + assertTrue(mask.isInNet(ia.getAddress())); + + mask = new NetMask("192.168.1/24"); + assertTrue(mask.isInNet("192.168.1.20")); + assertTrue(mask.isInNet("192.168.1.255")); + assertFalse(mask.isInNet("192.168.2.20")); + + mask = new NetMask("192.168.1/31"); + assertFalse(mask.isInNet("192.168.2.20")); + assertFalse(mask.isInNet("192.168.1.20")); + assertTrue(mask.isInNet("192.168.1.1")); + assertFalse(mask.isInNet("192.168.1.2")); + + mask = new NetMask("192/8"); + assertTrue(mask.isInNet("192.168.1.1")); + assertTrue(mask.isInNet("192.1.1.1")); + assertFalse(mask.isInNet("193.168.1.1")); + + mask = new NetMask("/0"); + assertTrue(mask.isInNet("193.168.1.1")); + + String msg = "Should throw " + MaskFormatException.class.getSimpleName(); + try { + mask = new NetMask("256.256.256.256"); + Assert.assertTrue(msg,false); + } catch (MaskFormatException e) { + Assert.assertTrue(msg,true); + } + } + +} diff --git a/auth/auth-core/src/test/java/org/onap/aaf/auth/validation/test/JU_Validator.java b/auth/auth-core/src/test/java/org/onap/aaf/auth/validation/test/JU_Validator.java new file mode 100644 index 00000000..fb59a54d --- /dev/null +++ b/auth/auth-core/src/test/java/org/onap/aaf/auth/validation/test/JU_Validator.java @@ -0,0 +1,204 @@ +/******************************************************************************* + * ============LICENSE_START==================================================== + * * org.onap.aaf + * * =========================================================================== + * * Copyright © 2017 AT&T Intellectual Property. All rights reserved. + * * =========================================================================== + * * 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==================================================== + * * + * * + ******************************************************************************/ +package org.onap.aaf.auth.validation.test; + +import static org.junit.Assert.*; +import static org.mockito.Mockito.*; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.regex.Pattern; + +import static org.mockito.Matchers.*; +import org.mockito.Mock; + +import org.junit.Before; +import org.junit.Test; +import org.junit.Test; +import org.onap.aaf.auth.env.AuthzTrans; +import org.onap.aaf.auth.env.AuthzTransOnlyFilter; +import org.onap.aaf.auth.validation.Validator; +import org.onap.aaf.cadi.principal.TaggedPrincipal; + +public class JU_Validator { + + Validator validator; + + @Before + public void setUp() { + validator = new Validator(); + } + + @Test + public void testNullOrBlank() { + validator.nullOrBlank(null, "str"); + validator.nullOrBlank("test", ""); + validator.nullOrBlank("test", null); + } + + @Test + public void testIsNull() { + Object o = new Object(); + validator.isNull(null, null); + validator.isNull(null, o); + } + + @Test + public void testDescription() throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException { + Class c = validator.getClass(); + Class[] cArg = new Class[2]; + cArg[0] = String.class; + cArg[1] = String.class; //Steps to test a protected method + Method descriptionMethod = c.getDeclaredMethod("description", cArg); + descriptionMethod.setAccessible(true); + descriptionMethod.invoke(validator,"test", "test1"); + descriptionMethod.invoke(validator,null, null); + descriptionMethod.invoke(validator,null, "[\\\\x25\\\\x28\\\\x29\\\\x2C-\\\\x2E\\\\x30-\\\\x39\\\\x3D\\\\x40-\\\\x5A\\\\x5F\\\\x61-\\\\x7A\\\\x20]+"); + + + } + + @Test + public void test() { + assertTrue(Validator.ACTION_CHARS.matcher("HowdyDoody").matches()); + assertFalse(Validator.ACTION_CHARS.matcher("Howd?yDoody").matches()); + assertTrue(Validator.ACTION_CHARS.matcher("_HowdyDoody").matches()); + assertTrue(Validator.INST_CHARS.matcher("HowdyDoody").matches()); + assertFalse(Validator.INST_CHARS.matcher("Howd?yDoody").matches()); + assertTrue(Validator.INST_CHARS.matcher("_HowdyDoody").matches()); + + // + assertTrue(Validator.ACTION_CHARS.matcher("*").matches()); + assertTrue(Validator.INST_CHARS.matcher("*").matches()); + assertFalse(Validator.ACTION_CHARS.matcher(":*").matches()); + assertTrue(Validator.INST_CHARS.matcher(":*").matches()); + assertFalse(Validator.ACTION_CHARS.matcher(":*:*").matches()); + assertTrue(Validator.INST_CHARS.matcher(":*:*").matches()); + + assertFalse(Validator.ACTION_CHARS.matcher(":hello").matches()); + assertTrue(Validator.INST_CHARS.matcher(":hello").matches()); + assertFalse(Validator.INST_CHARS.matcher("hello:").matches()); + assertFalse(Validator.INST_CHARS.matcher("hello:d").matches()); + + assertFalse(Validator.ACTION_CHARS.matcher(":hello:*").matches()); + assertTrue(Validator.INST_CHARS.matcher(":hello:*").matches()); + assertFalse(Validator.ACTION_CHARS.matcher(":hello:d*:*").matches()); + assertFalse(Validator.INST_CHARS.matcher(":hello:d*d:*").matches()); + assertTrue(Validator.INST_CHARS.matcher(":hello:d*:*").matches()); + assertFalse(Validator.ACTION_CHARS.matcher("HowdyDoody*").matches()); + assertFalse(Validator.INST_CHARS.matcher("Howdy*Doody").matches()); + assertTrue(Validator.INST_CHARS.matcher("HowdyDoody*").matches()); + assertFalse(Validator.ACTION_CHARS.matcher("*HowdyDoody").matches()); + assertFalse(Validator.INST_CHARS.matcher("*HowdyDoody").matches()); + assertFalse(Validator.ACTION_CHARS.matcher(":h*").matches()); + assertFalse(Validator.INST_CHARS.matcher(":h*h*").matches()); + assertTrue(Validator.INST_CHARS.matcher(":h*").matches()); + assertFalse(Validator.ACTION_CHARS.matcher(":h:h*:*").matches()); + assertTrue(Validator.INST_CHARS.matcher(":h:h*:*").matches()); + assertFalse(Validator.INST_CHARS.matcher(":h:h*h:*").matches()); + assertFalse(Validator.INST_CHARS.matcher(":h:h*h*:*").matches()); + assertFalse(Validator.ACTION_CHARS.matcher(":h:*:*h").matches()); + assertFalse(Validator.INST_CHARS.matcher(":h:*:*h").matches()); + assertTrue(Validator.INST_CHARS.matcher(":com.test.*:ns:*").matches()); + + + assertFalse(Validator.ACTION_CHARS.matcher("1234+235gd").matches()); + assertTrue(Validator.ACTION_CHARS.matcher("1234-235gd").matches()); + assertTrue(Validator.ACTION_CHARS.matcher("1234-23_5gd").matches()); + assertTrue(Validator.ACTION_CHARS.matcher("1234-235g,d").matches()); + assertTrue(Validator.ACTION_CHARS.matcher("1234-235gd(Version12)").matches()); + assertFalse(Validator.ACTION_CHARS.matcher("123#4-23@5g:d").matches()); + assertFalse(Validator.ACTION_CHARS.matcher("123#4-23@5g:d").matches()); + assertFalse(Validator.ACTION_CHARS.matcher("1234-23 5gd").matches()); + assertFalse(Validator.ACTION_CHARS.matcher("1234-235gd ").matches()); + assertFalse(Validator.ACTION_CHARS.matcher(" 1234-235gd").matches()); + assertFalse(Validator.ACTION_CHARS.matcher("").matches()); + assertFalse(Validator.ACTION_CHARS.matcher(" ").matches()); + + // Allow % and = (Needed for Escaping & Base64 usages) jg + assertTrue(Validator.ACTION_CHARS.matcher("1234%235g=d").matches()); + assertFalse(Validator.ACTION_CHARS.matcher(":1234%235g=d").matches()); + assertTrue(Validator.INST_CHARS.matcher("1234%235g=d").matches()); + assertTrue(Validator.INST_CHARS.matcher(":1234%235g=d").matches()); + assertTrue(Validator.INST_CHARS.matcher(":1234%235g=d:%20==").matches()); + assertTrue(Validator.INST_CHARS.matcher(":1234%235g=d:==%20:=%23").matches()); + assertTrue(Validator.INST_CHARS.matcher(":1234%235g=d:*:=%23").matches()); + assertTrue(Validator.INST_CHARS.matcher(":1234%235g=d:==%20:*").matches()); + assertTrue(Validator.INST_CHARS.matcher(":*:==%20:*").matches()); + + // Allow / instead of : (more natural instance expression) jg + assertFalse(Validator.INST_CHARS.matcher("1234/a").matches()); + assertTrue(Validator.INST_CHARS.matcher("/1234/a").matches()); + assertTrue(Validator.INST_CHARS.matcher("/1234/*/a/").matches()); + assertTrue(Validator.INST_CHARS.matcher("/1234//a").matches()); + assertFalse(Validator.ACTION_CHARS.matcher("1234/a").matches()); + assertFalse(Validator.ACTION_CHARS.matcher("/1234/*/a/").matches()); + assertFalse(Validator.ACTION_CHARS.matcher("1234//a").matches()); + + + assertFalse(Validator.INST_CHARS.matcher("1234+235gd").matches()); + assertTrue(Validator.INST_CHARS.matcher("1234-235gd").matches()); + assertTrue(Validator.INST_CHARS.matcher("1234-23_5gd").matches()); + assertTrue(Validator.INST_CHARS.matcher("1234-235g,d").matches()); + assertTrue(Validator.INST_CHARS.matcher("m1234@shb.dd.com").matches()); + assertTrue(Validator.INST_CHARS.matcher("1234-235gd(Version12)").matches()); + assertFalse(Validator.INST_CHARS.matcher("123#4-23@5g:d").matches()); + assertFalse(Validator.INST_CHARS.matcher("123#4-23@5g:d").matches()); + assertFalse(Validator.INST_CHARS.matcher("").matches()); + + + for( char c=0x20;c<0x7F;++c) { + boolean b; + switch(c) { + case '?': + case '|': + case '*': + continue; // test separately + case '~': + case ',': + b = false; + break; + default: + b=true; + } + } + + assertFalse(Validator.ID_CHARS.matcher("abc").matches()); + assertFalse(Validator.ID_CHARS.matcher("").matches()); + assertTrue(Validator.ID_CHARS.matcher("abc@att.com").matches()); + assertTrue(Validator.ID_CHARS.matcher("ab-me@att.com").matches()); + assertTrue(Validator.ID_CHARS.matcher("ab-me_.x@att._-com").matches()); + + assertFalse(Validator.NAME_CHARS.matcher("ab-me_.x@att._-com").matches()); + assertTrue(Validator.NAME_CHARS.matcher("ab-me").matches()); + assertTrue(Validator.NAME_CHARS.matcher("ab-me_.xatt._-com").matches()); + + + // 7/22/2016 + assertTrue(Validator.INST_CHARS.matcher( + "/!com.att.*/role/write").matches()); + assertTrue(Validator.INST_CHARS.matcher( + ":!com.att.*:role:write").matches()); + + } + +} diff --git a/auth/auth-core/test/sample.identities.dat b/auth/auth-core/test/sample.identities.dat new file mode 100644 index 00000000..39d18a12 --- /dev/null +++ b/auth/auth-core/test/sample.identities.dat @@ -0,0 +1,27 @@ +# +# Sample Identities.dat +# This file is for use with the "Default Organization". It is a simple mechanism to have a basic ILM structure to use with +# out-of-the-box tire-kicking, or even for Small companies +# +# For Larger Companies, you will want to create a new class implementing the "Organization" interface, making calls to your ILM, or utilizing +# batch feeds, as is appropriate for your company. +# +# Example Field Layout. note, in this example, Application IDs and People IDs are mixed. You may want to split +# out AppIDs, choose your own status indicators, or whatever you use. +# 0 - unique ID +# 1 - full name +# 2 - first name +# 3 - last name +# 4 - phone +# 5 - official email +# 6 - employment status e=employee, c=contractor, a=application, n=no longer with company +# 7 - responsible to (i.e Supervisor for People, or AppOwner, if it's an App ID) +# + +iowna|Ima D. Owner|Ima|Owner|314-123-2000|ima.d.owner@osaaf.com|e| +mmanager|Mark D. Manager|Mark|Manager|314-123-1234|mark.d.manager@osaaf.com|e|iowna +bdevl|Robert D. Developer|Bob|Developer|314-123-1235|bob.d.develper@osaaf.com|e|mmanager +mmarket|Mary D. Marketer|Mary|Marketer|314-123-1236|mary.d.marketer@osaaf.com|e|mmanager +ccontra|Clarice D. Contractor|Clarice|Contractor|314-123-1237|clarice.d.contractor@osaaf.com|c|mmanager +iretired|Ira Lee M. Retired|Ira|Retired|314-123-1238|clarice.d.contractor@osaaf.com|n|mmanager +osaaf|ID of AAF|||||a|bdevl diff --git a/auth/auth-deforg/.gitignore b/auth/auth-deforg/.gitignore new file mode 100644 index 00000000..ad5605e4 --- /dev/null +++ b/auth/auth-deforg/.gitignore @@ -0,0 +1,5 @@ +/bin/ +/target/ +/.classpath +/.project +/.settings diff --git a/auth/auth-deforg/pom.xml b/auth/auth-deforg/pom.xml new file mode 100644 index 00000000..29de4fd3 --- /dev/null +++ b/auth/auth-deforg/pom.xml @@ -0,0 +1,184 @@ + + + + 4.0.0 + + parent + ../pom.xml + org.onap.aaf.auth + 2.1.0-SNAPSHOT + + + aaf-auth-deforg + AAF Auth Default Organization + Example Organization Module + jar + + + + Jonathan Gathman + jonathan.gathman@att.com + ATT + + Architect + Lead Developer + + + + Gabe Maurer + gabe.maurer@att.com + ATT + + Developer + + + + Ian Howell + ian.howell@att.com + ATT + + Developer + + + + + + + false + + + + + + org.onap.aaf.cadi + aaf-cadi-core + + + + org.onap.aaf.auth + aaf-auth-core + + + + javax.mail + mail + + + + + + + + org.apache.maven.plugins + maven-javadoc-plugin + 2.10.4 + + false + + + + attach-javadocs + + jar + + + + + + org.sonatype.plugins + nexus-staging-maven-plugin + 1.6.7 + true + + ${nexusproxy} + 176c31dfe190a + ecomp-staging + + + + org.jacoco + jacoco-maven-plugin + ${jacoco.version} + + + **/gen/** + **/generated-sources/** + **/yang-gen/** + **/pax/** + + + + + + pre-unit-test + + prepare-agent + + + ${project.build.directory}/code-coverage/jacoco-ut.exec + surefireArgLine + + + + + + post-unit-test + test + + report + + + ${project.build.directory}/code-coverage/jacoco-ut.exec + ${project.reporting.outputDirectory}/jacoco-ut + + + + pre-integration-test + pre-integration-test + + prepare-agent + + + ${project.build.directory}/code-coverage/jacoco-it.exec + failsafeArgLine + + + + + post-integration-test + post-integration-test + + report + + + ${project.build.directory}/code-coverage/jacoco-it.exec + ${project.reporting.outputDirectory}/jacoco-it + + + + + + + + + diff --git a/auth/auth-deforg/src/main/java/org/onap/aaf/org/DefaultOrg.java b/auth/auth-deforg/src/main/java/org/onap/aaf/org/DefaultOrg.java new file mode 100644 index 00000000..63e83901 --- /dev/null +++ b/auth/auth-deforg/src/main/java/org/onap/aaf/org/DefaultOrg.java @@ -0,0 +1,666 @@ +/******************************************************************************* + * ============LICENSE_START==================================================== + * * org.onap.aaf + * * =========================================================================== + * * Copyright © 2017 AT&T Intellectual Property. All rights reserved. + * * =========================================================================== + * * 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==================================================== + * * + * * + ******************************************************************************/ +package org.onap.aaf.org; + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Date; +import java.util.GregorianCalendar; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.regex.Pattern; + +import javax.mail.Address; +import javax.mail.Message; +import javax.mail.MessagingException; +import javax.mail.Session; +import javax.mail.Transport; +import javax.mail.internet.InternetAddress; +import javax.mail.internet.MimeMessage; + +import org.onap.aaf.auth.env.AuthzTrans; +import org.onap.aaf.auth.org.EmailWarnings; +import org.onap.aaf.auth.org.Executor; +import org.onap.aaf.auth.org.Organization; +import org.onap.aaf.auth.org.OrganizationException; +import org.onap.aaf.cadi.util.FQI; +import org.onap.aaf.misc.env.Env; + +public class DefaultOrg implements Organization { + private static final String AAF_DATA_DIR = "aaf_data_dir"; + private static final String PROPERTY_IS_REQUIRED = " property is Required"; + // Package on Purpose + final String domain; + final String atDomain; + final String realm; + + private final String NAME,mailHost,mailFrom; + + public DefaultOrg(Env env, String realm) throws OrganizationException { + this.realm = realm; + domain=FQI.reverseDomain(realm); + atDomain = '@'+domain; + String s; + NAME=env.getProperty(realm + ".name","Default Organization"); + mailHost = env.getProperty(s=(realm + ".mailHost"), null); + if(mailHost==null) { + throw new OrganizationException(s + PROPERTY_IS_REQUIRED); + } + mailFrom = env.getProperty(s=(realm + ".mailFrom"), null); + if(mailFrom==null) { + throw new OrganizationException(s + PROPERTY_IS_REQUIRED); + } + + System.getProperties().setProperty("mail.smtp.host",mailHost); + System.getProperties().setProperty("mail.user", mailFrom); + // Get the default Session object. + session = Session.getDefaultInstance(System.getProperties()); + + try { + String defFile; + String temp=env.getProperty(defFile = (getClass().getName()+".file")); + File fIdentities=null; + if(temp==null) { + temp = env.getProperty(AAF_DATA_DIR); + if(temp!=null) { + env.warn().log(defFile, "is not defined. Using default: ",temp+"/identities.dat"); + File dir = new File(temp); + fIdentities=new File(dir,"identities.dat"); + if(!fIdentities.exists()) { + env.warn().log("No",fIdentities.getCanonicalPath(),"exists. Creating."); + if(!dir.exists()) { + dir.mkdirs(); + } + fIdentities.createNewFile(); + } + } + } else { + fIdentities = new File(temp); + if(!fIdentities.exists()) { + String dataDir = env.getProperty(AAF_DATA_DIR); + if(dataDir!=null) { + fIdentities = new File(dataDir,temp); + } + } + } + + if(fIdentities!=null && fIdentities.exists()) { + identities = new Identities(fIdentities); + } else { + throw new OrganizationException(fIdentities.getCanonicalPath() + " does not exist."); + } + } catch (IOException e) { + throw new OrganizationException(e); + } + } + + // Implement your own Delegation System + static final List NULL_DELEGATES = new ArrayList(); + + public Identities identities; + private boolean dryRun; + private Session session; + public enum Types {Employee, Contractor, Application, NotActive}; + private final static Set typeSet; + + static { + typeSet = new HashSet(); + for(Types t : Types.values()) { + typeSet.add(t.name()); + } + } + + private static final EmailWarnings emailWarnings = new DefaultOrgWarnings(); + + @Override + public String getName() { + return NAME; + } + + @Override + public String getRealm() { + return realm; + } + + @Override + public String getDomain() { + return domain; + } + + @Override + public DefaultOrgIdentity getIdentity(AuthzTrans trans, String id) throws OrganizationException { + int at = id.indexOf('@'); + return new DefaultOrgIdentity(trans,at<0?id:id.substring(0, at),this); + } + + // Note: Return a null if found; return a String Message explaining why not found. + @Override + public String isValidID(final AuthzTrans trans, final String id) { + try { + DefaultOrgIdentity u = getIdentity(trans,id); + return (u==null||!u.isFound())?id + "is not an Identity in " + getName():null; + } catch (OrganizationException e) { + return getName() + " could not lookup " + id + ": " + e.getLocalizedMessage(); + } + } + // Possible ID Pattern + // private static final Pattern ID_PATTERN=Pattern.compile("([\\w.-]+@[\\w.-]+).{4-13}"); + // Another one: ID_PATTERN = "(a-z[a-z0-9]{5-8}@.*).{4-13}"; + + @Override + public boolean isValidCred(final AuthzTrans trans, final String id) { + // have domain? + int at = id.indexOf('@'); + String sid; + if(at > 0) { + // Use this to prevent passwords to any but THIS domain. +// if(!id.regionMatches(at+1, domain, 0, id.length()-at-1)) { +// return false; +// } + sid = id.substring(0,at); + } else { + sid = id; + } + // We'll validate that it exists, rather than check patterns. + + return isValidID(trans, sid)==null; + // Check Pattern (if checking existing is too long) + // if(id.endsWith(SUFFIX) && ID_PATTERN.matcher(id).matches()) { + // return true; + // } + // return false; + } + + private static final String SPEC_CHARS = "!@#$%^*-+?/,:;."; + private static final Pattern PASS_PATTERN=Pattern.compile("((?=.*\\d)(?=.*[a-z])(?=.*[A-Z])(?=.*[" + SPEC_CHARS +"]).{6,20})"); + /** + * Attribution: from mkyong.com + * ( # Start of group + * (?=.*\d) # must contains one digit from 0-9 + * (?=.*[a-z]) # must contains one lowercase characters + * (?=.*[A-Z]) # must contains one uppercase characters + * (?=.*[@#$%]) # must contains one special symbols in the list SPEC_CHARS + * . # match anything with previous condition checking + * {6,20} # length at least 6 characters and maximum of 20 + * ) # End of group + */ + @Override + public String isValidPassword(final AuthzTrans trans, final String user, final String password, final String... prev) { + for(String p : prev) { + if(password.contains(p)) { // A more sophisticated algorithm might be better. + return "Password too similar to previous passwords"; + } + } + // If you have an Organization user/Password scheme, replace the following + if(PASS_PATTERN.matcher(password).matches()) { + return ""; + } + return "Password does not match " + NAME + " Password Standards"; + } + + private static final String[] rules = new String[] { + "Passwords must contain one digit from 0-9", + "Passwords must contain one lowercase character", + "Passwords must contain one uppercase character", + "Passwords must contain one special symbols in the list \""+ SPEC_CHARS + '"', + "Passwords must be between 6 and 20 chars in length" + }; + + @Override + public String[] getPasswordRules() { + return rules; + } + + @Override + public Set getIdentityTypes() { + return typeSet; + } + + @Override + public Response notify(AuthzTrans trans, Notify type, String url, String[] identities, String[] ccs, String summary, Boolean urgent) { + String system = trans.getProperty("CASS_ENV", ""); + + ArrayList toList = new ArrayList(); + Identity identity; + if (identities != null) { + for (String user : identities) { + try { + identity = getIdentity(trans, user); + if (identity == null) { + trans.error().log( + "Failure to obtain User " + user + " for " + + getName()); + } else { + toList.add(identity.email()); + } + } catch (Exception e) { + trans.error().log( + e, + "Failure to obtain User " + user + " for " + + getName()); + } + } + } + + if (toList.isEmpty()) { + trans.error().log("No Users listed to email"); + return Response.ERR_NotificationFailure; + } + + ArrayList ccList = new ArrayList(); + + // If we're sending an urgent email, CC the user's supervisor + // + if (urgent) { + trans.info().log("urgent msg for: " + identities[0]); + try { + List supervisors = getApprovers(trans, identities[0]); + for (Identity us : supervisors) { + trans.info().log("supervisor: " + us.email()); + ccList.add(us.email()); + } + } catch (Exception e) { + trans.error().log(e, + "Failed to find supervisor for " + identities[0]); + } + } + + if (ccs != null) { + for (String user : ccs) { + try { + identity = getIdentity(trans, user); + ccList.add(identity.email()); + } catch (Exception e) { + trans.error().log( + e, + "Failure to obtain User " + user + " for " + + getName()); + } + } + } + + if (summary == null) { + summary = ""; + } + + switch (type) { + case Approval: + try { + sendEmail(trans, toList, ccList, + "AAF Approval Notification " + + (system.length() == 0 ? "" : "(ENV: " + + system + ")"), + "AAF is the " + + NAME + + "System for Fine-Grained Authorizations. You are being asked to Approve" + + (system.length() == 0 ? "" : " in the " + + system + " environment") + + " before AAF Actions can be taken.\n\n" + + "Please follow this link: \n\n\t" + url + + "\n\n" + summary, urgent); + } catch (Exception e) { + trans.error().log(e, "Failure to send Email"); + return Response.ERR_NotificationFailure; + } + break; + case PasswordExpiration: + try { + sendEmail(trans, + toList, + ccList, + "AAF Password Expiration Warning " + + (system.length() == 0 ? "" : "(ENV: " + + system + ")"), + "AAF is the " + + NAME + + " System for Authorizations.\n\nOne or more passwords will expire soon or have expired" + + (system.length() == 0 ? "" : " in the " + + system + " environment") + + ".\n\nPasswords expired for more than 30 days without action are subject to deletion.\n\n" + + "Please follow each link to add a New Password with Expiration Date. Either are valid until expiration. " + + "Use this time to change the passwords on your system. If issues, reply to this email.\n\n" + + summary, urgent); + } catch (Exception e) { + trans.error().log(e, "Failure to send Email"); + return Response.ERR_NotificationFailure; + } + break; + + case RoleExpiration: + try { + sendEmail( + trans, + toList, + ccList, + "AAF Role Expiration Warning " + + (system.length() == 0 ? "" : "(ENV: " + + system + ")"), + "AAF is the " + + NAME + + " System for Authorizations. One or more roles will expire soon" + + (system.length() == 0 ? "" : " in the " + + system + " environment") + + ".\n\nRoles expired for more than 30 days are subject to deletion." + + "Please follow this link the GUI Command line, and either 'extend' or 'del' the user in the role.\n" + + "If issues, reply to this email.\n\n\t" + url + + "\n\n" + summary, urgent); + } catch (Exception e) { + trans.error().log(e, "Failure to send Email"); + return Response.ERR_NotificationFailure; + } + break; + default: + return Response.ERR_NotImplemented; + } + return Response.OK; + } + + @Override + public int sendEmail(AuthzTrans trans, List toList, List ccList, String subject, String body, + Boolean urgent) throws OrganizationException { + int status = 1; + + List to = new ArrayList(); + for(String em : toList) { + if(em.indexOf('@')<0) { + to.add(new DefaultOrgIdentity(trans, em, this).email()); + } else { + to.add(em); + } + } + + List cc = new ArrayList(); + if(ccList!=null && !ccList.isEmpty()) { + for(String em : ccList) { + if(em.indexOf('@')<0) { + cc.add(new DefaultOrgIdentity(trans, em, this).email()); + } else { + cc.add(em); + } + } + } + + + // for now, I want all emails so we can see what goes out. Remove later + if (!ccList.contains(mailFrom)) { + ccList.add(mailFrom); + } + + try { + // Create a default MimeMessage object. + MimeMessage message = new MimeMessage(session); + + // Set From: header field of the header. + message.setFrom(new InternetAddress(mailFrom)); + + if (!dryRun) { + // Set To: header field of the header. This is a required field + // and calling module should make sure that it is not null or + // blank + message.addRecipients(Message.RecipientType.TO,getAddresses(to)); + + // Set CC: header field of the header. + if ((ccList != null) && (ccList.size() > 0)) { + message.addRecipients(Message.RecipientType.CC,getAddresses(cc)); + } + + // Set Subject: header field + message.setSubject(subject); + + if (urgent) { + message.addHeader("X-Priority", "1"); + } + + // Now set the actual message + message.setText(body); + } else { + // override recipients + message.addRecipients(Message.RecipientType.TO, + InternetAddress.parse(mailFrom)); + + // Set Subject: header field + message.setSubject("[TESTMODE] " + subject); + + if (urgent) { + message.addHeader("X-Priority", "1"); + } + + ArrayList newBody = new ArrayList(); + + Address temp[] = getAddresses(to); + String headerString = "TO:\t" + InternetAddress.toString(temp) + "\n"; + + temp = getAddresses(cc); + headerString += "CC:\t" + InternetAddress.toString(temp) + "\n"; + + newBody.add(headerString); + + newBody.add("Text: \n"); + + newBody.add(body); + String outString = ""; + for (String s : newBody) { + outString += s + "\n"; + } + + message.setText(outString); + } + // Send message + Transport.send(message); + status = 0; + + } catch (MessagingException mex) { + throw new OrganizationException("Exception send email message " + + mex.getMessage()); + } + + return status; + } + + /** + * Default Policy is to set to 6 Months for Notification Types. + * add others/change as required + */ + @Override + public Date whenToValidate(Notify type, Date lastValidated) { + switch(type) { + case Approval: + case PasswordExpiration: + return null; + default: + GregorianCalendar gc = new GregorianCalendar(); + gc.setTime(lastValidated); + gc.add(GregorianCalendar.MONTH, 6); // 6 month policy + return gc.getTime(); + } + } + + @Override + public GregorianCalendar expiration(GregorianCalendar gc, Expiration exp, String... extra) { + GregorianCalendar now = new GregorianCalendar(); + GregorianCalendar rv = gc==null?now:(GregorianCalendar)gc.clone(); + switch (exp) { + case ExtendPassword: + // Extending Password give 5 extra days, max 8 days from now + rv.add(GregorianCalendar.DATE, 5); + now.add(GregorianCalendar.DATE, 8); + if(rv.after(now)) { + rv = now; + } + break; + case Future: + // Future requests last 15 days. + now.add(GregorianCalendar.DATE, 15); + rv = now; + break; + case Password: + // Passwords expire in 90 days + now.add(GregorianCalendar.DATE, 90); + rv = now; + break; + case TempPassword: + // Temporary Passwords last for 12 hours. + now.add(GregorianCalendar.DATE, 90); + rv = now; + break; + case UserDelegate: + // Delegations expire max in 2 months, renewable to 3 + rv.add(GregorianCalendar.MONTH, 2); + now.add(GregorianCalendar.MONTH, 3); + if(rv.after(now)) { + rv = now; + } + break; + case UserInRole: + // Roles expire in 6 months + now.add(GregorianCalendar.MONTH, 6); + rv = now; + break; + default: + // Unless other wise set, 6 months is default + now.add(GregorianCalendar.MONTH, 6); + rv = now; + break; + } + return rv; + } + + @Override + public EmailWarnings emailWarningPolicy() { + return emailWarnings; + } + + /** + * Assume the Supervisor is the Approver. + */ + @Override + public List getApprovers(AuthzTrans trans, String user) throws OrganizationException { + Identity orgIdentity = getIdentity(trans, user); + List orgIdentitys = new ArrayList(); + if(orgIdentity!=null) { + Identity supervisor = orgIdentity.responsibleTo(); + if(supervisor!=null) { + orgIdentitys.add(supervisor); + } + } + return orgIdentitys; + } + + @Override + public String getApproverType() { + return "supervisor"; + } + + @Override + public int startOfDay() { + // TODO Auto-generated method stub + return 0; + } + + @Override + public boolean canHaveMultipleCreds(String id) { + // External entities are likely mono-password... if you change it, it is a global change. + // This is great for people, but horrible for Applications. + // + // AAF's Password can have multiple Passwords, each with their own Expiration Date. + // For Default Org, we'll assume true for all, but when you add your external + // Identity stores, you need to return "false" if they cannot support multiple Passwords like AAF + return true; + } + + @Override + public String validate(AuthzTrans trans, Policy policy, Executor executor, String... vars) throws OrganizationException { + switch(policy) { + case OWNS_MECHID: + case CREATE_MECHID: + if(vars.length>0) { + DefaultOrgIdentity thisID = getIdentity(trans,vars[0]); + if("a".equals(thisID.identity.status)) { // MechID + DefaultOrgIdentity requestor = getIdentity(trans, trans.user()); + if(requestor!=null) { + Identity mechid = getIdentity(trans, vars[0]); + if(mechid!=null) { + Identity sponsor = mechid.responsibleTo(); + if(sponsor!=null && requestor.equals(sponsor.fullID())) { + return null; + } else { + return trans.user() + " is not the Sponsor of MechID " + vars[0]; + } + } + } + } + } + return null; + + case CREATE_MECHID_BY_PERM_ONLY: + return getName() + " only allows sponsors to create MechIDs"; + + default: + return policy.name() + " is unsupported at " + getName(); + } + } + + @Override + public boolean isTestEnv() { + return false; + } + + @Override + public void setTestMode(boolean dryRun) { + this.dryRun = dryRun; + } + + /** + * Convert the delimiter String into Internet addresses with the default + * delimiter of ";" + * @param strAddress + * @return + */ + private Address[] getAddresses(List strAddress) throws OrganizationException { + return this.getAddresses(strAddress,";"); + } + /** + * Convert the delimiter String into Internet addresses with the + * delimiter of provided + * @param strAddress + * @param delimiter + * @return + */ + private Address[] getAddresses(List strAddresses, String delimiter) throws OrganizationException { + Address[] addressArray = new Address[strAddresses.size()]; + int count = 0; + for (String addr : strAddresses) + { + try{ + addressArray[count] = new InternetAddress(addr); + count++; + }catch(Exception e){ + throw new OrganizationException("Failed to parse the email address "+ addr +": "+e.getMessage()); + } + } + return addressArray; + } + + + } diff --git a/auth/auth-deforg/src/main/java/org/onap/aaf/org/DefaultOrgIdentity.java b/auth/auth-deforg/src/main/java/org/onap/aaf/org/DefaultOrgIdentity.java new file mode 100644 index 00000000..6d9003fd --- /dev/null +++ b/auth/auth-deforg/src/main/java/org/onap/aaf/org/DefaultOrgIdentity.java @@ -0,0 +1,170 @@ +/******************************************************************************* + * ============LICENSE_START==================================================== + * * org.onap.aaf + * * =========================================================================== + * * Copyright © 2017 AT&T Intellectual Property. All rights reserved. + * * =========================================================================== + * * 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==================================================== + * * + * * + ******************************************************************************/ +package org.onap.aaf.org; + +import java.io.IOException; +import java.util.List; + +import org.onap.aaf.auth.env.AuthzTrans; +import org.onap.aaf.auth.local.AbsData.Reuse; +import org.onap.aaf.auth.org.Organization; +import org.onap.aaf.auth.org.OrganizationException; +import org.onap.aaf.auth.org.Organization.Identity; +import org.onap.aaf.cadi.config.Config; +import org.onap.aaf.org.Identities.Data; + +/** + * Org Users are essential representations of Identities within the Org. Since this is a highly individual + * thing for most Orgs, i.e. some use LDAP, some need feed, some use something else, this object will allow + * the Organization to connect to their own Identity systems... + * + * + */ +public class DefaultOrgIdentity implements Identity { + private static final String CONTRACTOR = "c"; + private static final String EMPLOYEE = "e"; + private static final String APPLICATION = "a"; + private static final String NON_ACTIVE = "n"; + + private final static int TIMEOUT = Integer.parseInt(Config.AAF_CONN_TIMEOUT_DEF); + + private DefaultOrg org; + //package on purpose + Data identity; + private AuthzTrans trans; + + public DefaultOrgIdentity(AuthzTrans trans, String key, DefaultOrg dorg) throws OrganizationException { + this.trans = trans; + org = dorg; + identity=null; + try { + org.identities.open(trans, TIMEOUT); + try { + Reuse r = org.identities.reuse(); + int at = key.indexOf(dorg.atDomain); + String search; + if(at>=0) { + search = key.substring(0,at); + } else { + search = key; + } + identity = org.identities.find(search, r); + if(identity==null) { + identity = Identities.NO_DATA; + } + } finally { + org.identities.close(trans); + } + } catch (IOException e) { + throw new OrganizationException(e); + } + } + + @Override + public boolean equals(Object b) { + if(b instanceof DefaultOrgIdentity) { + return identity.id.equals(((DefaultOrgIdentity)b).identity.id); + } + return false; + } + + @Override + public String id() { + return identity.id; + } + + @Override + public String fullID() { + return identity.id+'@'+org.getDomain(); + } + + @Override + public String type() { + switch(identity.status) { + case EMPLOYEE: return DefaultOrg.Types.Employee.name(); + case CONTRACTOR: return DefaultOrg.Types.Contractor.name(); + case APPLICATION: return DefaultOrg.Types.Application.name(); + case NON_ACTIVE: return DefaultOrg.Types.NotActive.name(); + default: + return "Unknown"; + } + } + + @Override + public Identity responsibleTo() throws OrganizationException { + if("".equals(identity.responsibleTo) && isFound()) { // cover the situation of Top Dog... reports to no-one. + return this; + } else { + return org.getIdentity(trans, identity.responsibleTo); + } + } + + @Override + public List delegate() { + //NOTE: implement Delegate system, if desired + return DefaultOrg.NULL_DELEGATES; + } + + @Override + public String email() { + return identity.email; + } + + @Override + public String fullName() { + return identity.name; + } + + @Override + public String firstName() { + return identity.fname; + } + + @Override + public String mayOwn() { + // Assume only Employees are responsible for Resources. + if(identity.status==null|| identity.status.length()==0) { + return "Identity must have valid status"; + } else if(EMPLOYEE.equals(identity.status)) { + return null; // This is "Yes, is Responsible" + } else { + return "Reponsible Party must be an Employee"; + } + } + + @Override + public boolean isFound() { + return identity!=Identities.NO_DATA; // yes, object comparison intended + } + + @Override + public boolean isPerson() { + return !identity.status.equals(APPLICATION); + } + + @Override + public Organization org() { + return org; + } + + +} diff --git a/auth/auth-deforg/src/main/java/org/onap/aaf/org/DefaultOrgWarnings.java b/auth/auth-deforg/src/main/java/org/onap/aaf/org/DefaultOrgWarnings.java new file mode 100644 index 00000000..c04707ee --- /dev/null +++ b/auth/auth-deforg/src/main/java/org/onap/aaf/org/DefaultOrgWarnings.java @@ -0,0 +1,63 @@ +/******************************************************************************* + * ============LICENSE_START==================================================== + * * org.onap.aaf + * * =========================================================================== + * * Copyright © 2017 AT&T Intellectual Property. All rights reserved. + * * =========================================================================== + * * 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==================================================== + * * + * * + ******************************************************************************/ +package org.onap.aaf.org; + +import org.onap.aaf.auth.org.EmailWarnings; + +public class DefaultOrgWarnings implements EmailWarnings { + + @Override + public long credEmailInterval() + { + return 604800000L; // 7 days in millis 1000 * 86400 * 7 + } + + @Override + public long roleEmailInterval() + { + return 604800000L; // 7 days in millis 1000 * 86400 * 7 + } + + @Override + public long apprEmailInterval() { + return 259200000L; // 3 days in millis 1000 * 86400 * 3 + } + + @Override + public long credExpirationWarning() + { + return( 2592000000L ); // One month, in milliseconds 1000 * 86400 * 30 in milliseconds + } + + @Override + public long roleExpirationWarning() + { + return( 2592000000L ); // One month, in milliseconds 1000 * 86400 * 30 in milliseconds + } + + @Override + public long emailUrgentWarning() + { + return( 1209600000L ); // Two weeks, in milliseconds 1000 * 86400 * 14 in milliseconds + } + +} diff --git a/auth/auth-deforg/src/main/java/org/onap/aaf/org/Identities.java b/auth/auth-deforg/src/main/java/org/onap/aaf/org/Identities.java new file mode 100644 index 00000000..f3067fe6 --- /dev/null +++ b/auth/auth-deforg/src/main/java/org/onap/aaf/org/Identities.java @@ -0,0 +1,143 @@ +/******************************************************************************* + * ============LICENSE_START==================================================== + * * org.onap.aaf + * * =========================================================================== + * * Copyright © 2017 AT&T Intellectual Property. All rights reserved. + * * =========================================================================== + * * 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==================================================== + * * + * * + ******************************************************************************/ +package org.onap.aaf.org; + +import java.io.File; +import java.io.IOException; + +import org.onap.aaf.auth.local.AbsData; +import org.onap.aaf.auth.local.DataFile.Token.Field; + +/* + * Example User Data file, which can be modified for many different kinds of Data Feeds. + * + * Note: This has shown to be extremely effective in AT&T, an acknowledged very large organizations, + * because there is no need to synchronize records. AAF simply receives a Data Feed in Organization + * defined intervals. (You might want to check for validity, such as size, etc), then is copied into + * Data Directory. You will want to do so first creating a "lock" file. Assuming the File name is "users.dat", + * the Lock File is "users.lock". + * + * After the movement of the Datafile into place, it is best to remove the Index File, then remove the lock file. + * + * Note, Any AAF Programs needing this data WILL wait on the Lock file, so you should get fresh Data files + * in a "stage" directory, from WEB, or wherever, and then, after it is correct, do the following as fast as feasible. + * + * a) lock + * b) copy from stage + * c) remove idx + * d) unlock + * + * If the Index File is either non-existent or out of date from the Data File, it will be reindexed, which + * has proven to be a very quick function, even with large numbers of entries. + * + * This Sample Feed is set for a file with delimiter of "|". 512 is maximum expected line length. The "0" is the + * field offset for the "key" to the record, which, for user, should be the unique Organization Identity. + * + */ +public class Identities extends AbsData { + public final static Data NO_DATA = new Data(); + + public Identities(File users) { + super(users,'|',512,0); + } + + /* + * Example Field Layout. note, in this example, Application IDs and People IDs are mixed. You may want to split + * out AppIDs, choose your own status indicators, or whatever you use. + * 0 - unique ID + * 1 - full name + * 2 - first name + * 3 - last name + * 4 - phone + * 5 - official email + * 6 - employment status e=employee, c=contractor, a=application, n=no longer with company + * 7 - responsible to (i.e Supervisor for People, or AppOwner, if it's an App ID) + */ + public static class Data { + public final String id; + public final String name; + public final String fname; + public final String lname; + public final String phone; + public final String email; + public final String status; + public final String responsibleTo; + + private Data(Field f) { + f.reset(); + id=f.next(); + name=f.next(); + fname=f.next(); + lname=f.next(); + phone=f.next(); + email=f.next(); + status=f.next(); + responsibleTo =f.next(); + } + + private Data() { + id = name = fname = lname = + phone = email = status = responsibleTo + = ""; + } + + public String toString() { + return id + '|' + + name + '|' + + lname + '|' + + fname + '|' + + phone + '|' + + email + '|' + + status + '|' + + responsibleTo; + } + + // Here, make up your own Methods which help you easily determine your Organization's structure + // in your Organization Object + public boolean hasStatus(String possible) { + return possible.contains(status); + } + + public boolean isEmployee() { + return "e".equals(status); + } + + public boolean isContractor() { + return "c".equals(status); + } + + public boolean isApplication() { + return "a".equals(status); + } + } + + public Data find(Object key,Reuse r) throws IOException { + r.reset(); + // These are new, to allow for Thread Safety + int rec = ti.find(key,r,0); + if(rec<0) { + return null; + } + r.pos(rec); + return new Data(r.getFieldData()); + } +} diff --git a/auth/auth-deforg/src/test/java/org/onap/aaf/org/test/JU_DefaultOrg.java b/auth/auth-deforg/src/test/java/org/onap/aaf/org/test/JU_DefaultOrg.java new file mode 100644 index 00000000..72b15480 --- /dev/null +++ b/auth/auth-deforg/src/test/java/org/onap/aaf/org/test/JU_DefaultOrg.java @@ -0,0 +1,139 @@ +/******************************************************************************* + * ============LICENSE_START==================================================== + * * org.onap.aaf + * * =========================================================================== + * * Copyright © 2017 AT&T Intellectual Property. All rights reserved. + * * =========================================================================== + * * 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==================================================== + * * + * * + ******************************************************************************/ +package org.onap.aaf.org.test; + +import static org.junit.Assert.*; + +import java.io.File; +import java.util.Set; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Matchers; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.onap.aaf.auth.env.AuthzEnv; +import org.onap.aaf.auth.env.AuthzTrans; +import org.onap.aaf.auth.org.OrganizationException; +import org.onap.aaf.org.DefaultOrg; +import org.powermock.api.mockito.PowerMockito; +import org.powermock.modules.junit4.PowerMockRunner; + +@RunWith(PowerMockRunner.class) +public class JU_DefaultOrg { + + DefaultOrg defaultOrg; + //private DefaultOrg defaultOrgMock; + @Mock + AuthzEnv authzEnvMock; + + @Mock + AuthzTrans authzTransMock; + + @Mock + File fIdentitiesMock; + + private static final String PROPERTY_IS_REQUIRED = " property is Required"; + private static final String DOMAIN = "osaaf.com"; + private static final String REALM = "com.osaaf"; + private static final String NAME = "Default Organization"; + private static final String NO_PASS = NAME + " does not support Passwords. Use AAF"; + String mailHost,mailFromUserId,supportAddress; + private String SUFFIX; + String s; + String defFile; + + @Before + public void setUp() throws OrganizationException{ + MockitoAnnotations.initMocks(this); + PowerMockito.when(authzEnvMock.getProperty(s=(REALM + ".mailHost"), null)).thenReturn("hello"); + PowerMockito.when(authzEnvMock.getProperty(s=(REALM + ".supportEmail"), null)).thenReturn("notnull"); + PowerMockito.when(authzEnvMock.getProperty(Matchers.anyString())).thenReturn("src" + File.separator + "test" + File.separator + "resources" + File.separator + "test.txt"); + PowerMockito.when(fIdentitiesMock.exists()).thenReturn(true); + //PowerMockito.when((fIdentitiesMock!=null && fIdentitiesMock.exists())).thenReturn(true); + defaultOrg = new DefaultOrg(authzEnvMock, REALM); + } + + @Test //(expected=OrganizationException.class) + public void test() throws OrganizationException{ + //PowerMockito.when(authzEnvMock.getProperty(Matchers.anyString())).thenReturn(" "); + //defaultOrg = new DefaultOrg(authzEnvMock); + assertTrue(defaultOrg != null); + } + + + @Test //(expected=OrganizationException.class) + public void testMultipleCreds() throws OrganizationException{ + String id = "test"; + //PowerMockito.when(authzEnvMock.getProperty(Matchers.anyString())).thenReturn(" "); + //defaultOrg = new DefaultOrg(authzEnvMock); + boolean canHaveMultipleCreds; + canHaveMultipleCreds = defaultOrg.canHaveMultipleCreds(id ); + System.out.println("value of canHaveMultipleCreds: " + canHaveMultipleCreds); + assertTrue(canHaveMultipleCreds); + } + + + @Test + public void testGetIdentityTypes() throws OrganizationException{ + Set identityTypes = defaultOrg.getIdentityTypes(); + System.out.println("value of IdentityTypes: " + identityTypes); + assertTrue(identityTypes.size() == 4); + } + + + @Test + public void testGetRealm() throws OrganizationException{ + String realmTest = defaultOrg.getRealm(); + System.out.println("value of realm: " + realmTest); + assertTrue(realmTest == REALM); + } + + @Test + public void testGetName() throws OrganizationException{ + String testName = defaultOrg.getName(); + System.out.println("value of name: " + testName); + assertTrue(testName == NAME); + } + + + @Test + public void testGetDomain() throws OrganizationException{ + String testDomain = defaultOrg.getDomain(); + System.out.println("value of domain: " + testDomain); + assertTrue(testDomain == DOMAIN); + } + + // @Test + // public void testIsValidID(){ + // String Result = defaultOrg.isValidID(Matchers.anyString()); + // System.out.println("value of res " +Result); + // assertNotNull(Result); + // } + + @Test + public void notYetImplemented() { + fail("Tests in this file should not be trusted"); + } + +} diff --git a/auth/auth-deforg/src/test/java/org/onap/aaf/org/test/JU_DefaultOrgIdentity.java b/auth/auth-deforg/src/test/java/org/onap/aaf/org/test/JU_DefaultOrgIdentity.java new file mode 100644 index 00000000..1577d9e6 --- /dev/null +++ b/auth/auth-deforg/src/test/java/org/onap/aaf/org/test/JU_DefaultOrgIdentity.java @@ -0,0 +1,96 @@ +/******************************************************************************* + * ============LICENSE_START==================================================== + * * org.onap.aaf + * * =========================================================================== + * * Copyright © 2017 AT&T Intellectual Property. All rights reserved. + * * =========================================================================== + * * 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==================================================== + * * + * * + ******************************************************************************/ +package org.onap.aaf.org.test; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.onap.aaf.auth.env.AuthzTrans; +import org.onap.aaf.auth.org.OrganizationException; +import org.onap.aaf.auth.org.Organization.Identity; +import org.onap.aaf.org.DefaultOrg; +import org.onap.aaf.org.DefaultOrgIdentity; +import org.onap.aaf.org.Identities.Data; +import org.powermock.api.mockito.PowerMockito; +import org.powermock.modules.junit4.PowerMockRunner; + +@RunWith(PowerMockRunner.class) +public class JU_DefaultOrgIdentity { + + private DefaultOrgIdentity defaultOrgIdentity; + private DefaultOrgIdentity defaultOrgIdentityMock; + + @Mock + AuthzTrans authzTransMock; + + String key="key"; + + @Mock + private DefaultOrg defaultOrgMock; + @Mock + private Data dataMock; + @Mock + private Identity identityMock; + + @Before + public void setUp() throws OrganizationException{ + MockitoAnnotations.initMocks(this); + defaultOrgIdentityMock = PowerMockito.mock(DefaultOrgIdentity.class); + } + + @Test + public void testEquals(){ + Object b = null; + Boolean res = defaultOrgIdentityMock.equals(b); + System.out.println("value of res " +res); + } + + + @Test + public void testIsFound(){ + defaultOrgIdentityMock.isFound(); + System.out.println("value of found " +defaultOrgIdentityMock.isFound()); + assertFalse(defaultOrgIdentityMock.isFound()); + } + + @Test + public void testIsResponsible(){ + defaultOrgIdentityMock.mayOwn(); + System.out.println("value of res " +defaultOrgIdentityMock.mayOwn()); + assertNull(defaultOrgIdentityMock.mayOwn()); + } + + @Test + public void testFullName(){ + String fullName = defaultOrgIdentityMock.fullName(); + System.out.println("value of fullname " +fullName); + assertTrue(fullName == null); + } + + +} diff --git a/auth/auth-deforg/src/test/java/org/onap/aaf/org/test/JU_DefaultOrgWarnings.java b/auth/auth-deforg/src/test/java/org/onap/aaf/org/test/JU_DefaultOrgWarnings.java new file mode 100644 index 00000000..3b4d5543 --- /dev/null +++ b/auth/auth-deforg/src/test/java/org/onap/aaf/org/test/JU_DefaultOrgWarnings.java @@ -0,0 +1,83 @@ +/******************************************************************************* + * ============LICENSE_START==================================================== + * * org.onap.aaf + * * =========================================================================== + * * Copyright © 2017 AT&T Intellectual Property. All rights reserved. + * * =========================================================================== + * * 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==================================================== + * * + * * + ******************************************************************************/ +package org.onap.aaf.org.test; + +import static org.junit.Assert.assertEquals; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.MockitoAnnotations; +import org.onap.aaf.org.DefaultOrgWarnings; +import org.powermock.api.mockito.PowerMockito; +import org.powermock.modules.junit4.PowerMockRunner; + +@RunWith(PowerMockRunner.class) +public class JU_DefaultOrgWarnings { + + private DefaultOrgWarnings defaultOrgWarningsMock; + private DefaultOrgWarnings defaultOrgWarnings; + + + @Before + public void setUp(){ + MockitoAnnotations.initMocks(this); + + defaultOrgWarningsMock = PowerMockito.mock(DefaultOrgWarnings.class); + + defaultOrgWarnings = new DefaultOrgWarnings(); + } + + + @Test + public void testApprEmailInterval() { + + assertEquals(259200000, defaultOrgWarnings.apprEmailInterval() ); + } + + @Test + public void testCredEmailInterval() { + assertEquals(604800000, defaultOrgWarnings.credEmailInterval()); + + } + + @Test + public void testCredExpirationWarning() { + assertEquals(2592000000L, defaultOrgWarnings.credExpirationWarning()); + } + + @Test + public void testEmailUrgentWarning() { + assertEquals(1209600000L, defaultOrgWarnings.emailUrgentWarning()); + } + + @Test + public void testRoleEmailInterval() { + assertEquals(604800000L, defaultOrgWarnings.roleEmailInterval()); + } + + @Test + public void testRoleExpirationWarning() { + assertEquals(2592000000L, defaultOrgWarnings.roleExpirationWarning()); + } + +} diff --git a/auth/auth-deforg/src/test/java/org/onap/aaf/org/test/JU_Identities.java b/auth/auth-deforg/src/test/java/org/onap/aaf/org/test/JU_Identities.java new file mode 100644 index 00000000..e32ce844 --- /dev/null +++ b/auth/auth-deforg/src/test/java/org/onap/aaf/org/test/JU_Identities.java @@ -0,0 +1,110 @@ +/******************************************************************************* + * ============LICENSE_START==================================================== + * * org.onap.aaf + * * =========================================================================== + * * Copyright © 2017 AT&T Intellectual Property. All rights reserved. + * * =========================================================================== + * * 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==================================================== + * * + * * + ******************************************************************************/ +/** + * + */ +package org.onap.aaf.org.test; + +import java.io.File; +import java.io.IOException; + +import org.junit.After; +import org.junit.AfterClass; +import org.junit.Assert; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; +import org.onap.aaf.auth.env.AuthzEnv; +import org.onap.aaf.auth.env.AuthzTrans; +import org.onap.aaf.auth.local.AbsData.Reuse; +import org.onap.aaf.org.Identities; +import org.onap.aaf.org.Identities.Data; + +/** + * + */ +public class JU_Identities { + + private static final String DATA_IDENTITIES = "/opt/app/onap/data/identities.dat"; + private static File fids; + private static Identities ids; + private static AuthzEnv env; + + /** + * @throws java.lang.Exception + */ + @BeforeClass + public static void setUpBeforeClass() throws Exception { + env = new AuthzEnv(); + AuthzTrans trans = env.newTransNoAvg(); + // Note: utilize TimeTaken, from trans.start if you want to time. + fids = new File(DATA_IDENTITIES); + if(fids.exists()) { + ids = new Identities(fids); + ids.open(trans, 5000); + } else { + + throw new Exception("Data File for Tests, \"" + DATA_IDENTITIES + + "\" must exist before test can run. (Current dir is " + System.getProperty("user.dir") + ")"); + } + } + + /** + * @throws java.lang.Exception + */ + @AfterClass + public static void tearDownAfterClass() throws Exception { + AuthzTrans trans = env.newTransNoAvg(); + if(ids!=null) { + ids.close(trans); + } + } + + /** + * @throws java.lang.Exception + */ + @Before + public void setUp() throws Exception { + } + + /** + * @throws java.lang.Exception + */ + @After + public void tearDown() throws Exception { + } + + @Test + public void test() throws IOException { + Reuse reuse = ids.reuse(); // this object can be reused within the same thread. + Data id = ids.find("osaaf",reuse); + Assert.assertNotNull(id); + System.out.println(id); + + id = ids.find("mmanager",reuse); + Assert.assertNotNull(id); + System.out.println(id); + + //TODO Fill out JUnit with Tests of all Methods in "Data id" + } + +} diff --git a/auth/auth-deforg/src/test/resources/test.txt b/auth/auth-deforg/src/test/resources/test.txt new file mode 100644 index 00000000..e69de29b diff --git a/auth/auth-fs/.gitignore b/auth/auth-fs/.gitignore new file mode 100644 index 00000000..d3881782 --- /dev/null +++ b/auth/auth-fs/.gitignore @@ -0,0 +1,7 @@ +/target/ +/.classpath +/.settings +/.project +/Dockerfile +/dbuild +/drun diff --git a/auth/auth-fs/pom.xml b/auth/auth-fs/pom.xml new file mode 100644 index 00000000..11582b4b --- /dev/null +++ b/auth/auth-fs/pom.xml @@ -0,0 +1,122 @@ + + + + 4.0.0 + + org.onap.aaf.auth + parent + 2.1.0-SNAPSHOT + ../pom.xml + + + aaf-auth-fs + AAF Auth File Server (http) + Independent FileServer Component via HTTP (not S) for Public Files (i.e. CRLs) for AAF Auth + + + true + + + + + Jonathan Gathman + jonathan.gathman@att.com + ATT + + Architect + Lead Developer + + + + Gabe Maurer + gabe.maurer@att.com + ATT + + Developer + + + + Ian Howell + ian.howell@att.com + ATT + + Developer + + + + + + + org.onap.aaf.auth + aaf-auth-core + + + + org.onap.aaf.cadi + aaf-cadi-core + + + + + + + org.apache.maven.plugins + maven-deploy-plugin + + true + + + + org.codehaus.mojo + appassembler-maven-plugin + + + + org.onap.aaf.auth.fs.AAF_FS + fs + + cadi_prop_files=${project.conf_dir}/org.osaaf.fs.props + + + + + + + + + + + + + + nexus + attarch-releases + http://mavencentral.it.att.com:8084/nexus/content/repositories/attarch-releases + + + nexus + attarch-snapshots + http://mavencentral.it.att.com:8084/nexus/content/repositories/attarch-snapshots + + + diff --git a/auth/auth-fs/src/main/config/.gitignore b/auth/auth-fs/src/main/config/.gitignore new file mode 100644 index 00000000..e53ef90a --- /dev/null +++ b/auth/auth-fs/src/main/config/.gitignore @@ -0,0 +1 @@ +/log4j.properties diff --git a/auth/auth-fs/src/main/config/FileServer.props b/auth/auth-fs/src/main/config/FileServer.props new file mode 100644 index 00000000..9c123307 --- /dev/null +++ b/auth/auth-fs/src/main/config/FileServer.props @@ -0,0 +1,23 @@ +## +## AUTHZ API (authz-service) Properties +## + +hostname=_HOSTNAME_ + +## DISCOVERY (DME2) Parameters on the Command Line +AFT_LATITUDE=_AFT_LATITUDE_ +AFT_LONGITUDE=_AFT_LONGITUDE_ +AFT_ENVIRONMENT=_AFT_ENVIRONMENT_ +DEPLOYED_VERSION=_ARTIFACT_VERSION_ + +cadi_prop_files=/opt/app/aaf/common/com.att.aaf.common.props:/opt/app/aaf/common/com.att.aaf.props + +DMEServiceName=service=com.att.authz.authz-fs/version=_MAJOR_VER_._MINOR_VER_._PATCH_VER_/envContext=_ENV_CONTEXT_/routeOffer=_ROUTE_OFFER_ +AFT_DME2_PORT_RANGE=_AUTHZ_FS_PORT_RANGE_ +AFT_DME2_SSL_ENABLE=false +AFT_DME2_DISABLE_PERSISTENT_CACHE=true + +CFA_WebPath=/opt/app/aaf/public +CFA_ClearCommand=FmzYPpMY918MwE1hyacoiFSt +CFA_MaxSize=2000000 + diff --git a/auth/auth-fs/src/main/data/favicon.ico b/auth/auth-fs/src/main/data/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..3aea27221ca7732bc043a84f0cd2fcbfa3c80894 GIT binary patch literal 3638 zcmeHJXFycP7XB^~LWogf6kEiuV2nmIq-cVeL`~EXi6x3%5wRsgP_Y0mf?|QCH>Juh z9Tt{d$^r|7vXrH)TwFTRn>6X|&4Ru>U-BzI-mmxV-kmw;n|o%?+}ZP8fPx&9l`(-c z^1uqxTeN7>4paneiBFA~vLP}z1>z*wOieU@`57M{M~a;W5_y5}G6Y(xGQe^+f`n@d zS5qxiXL}<{lnasH9@Nygfp0zoQ2`I&X{`r`3(L{h-2ib02L>N?(b(DvIy(w+x94GWq#qS!MewvaiOMWjNd91>P7)43 z`|}Ws#mE+h!~eqDC@&H~9BGV#M0aGT^3X`fz}tE+vL5RoUla#{%TDC64nWBI9bGS) z5P4Mr{X@fGJLn_DYac4IS>RZ$L!CGXFIwx+(Oizkx@rvcw4%C7ih?i$6lH`Wnr#me z`vhp-O_ZiQ#LK=BbocZk>Ha!Y7e=D-Sv-bE$52(A3=!WMU2Qdx2t8nbQ5{i?Wf<;l z#`D^G)X}k|ts(ghBbG56gM$M|uv$QJEkh3b5X9jZQIP77#xfzECEZ15R}bo{i%}u+ zL04BZvV49dd$=FjDI7dYU|?u?2)zR@$v&<|h^HCCj3|tdGt>LB7abklsBLIPRY5pe zGZTC>W$-O#Vt8Z(T+3zXY%NDkO$}-#k>IlJAWrna*w`3E-a6>->nHcWKusmtgYYvb zO>@8)i90?%hGEhUkB(!A#2FnK!qCtVI!V6GWl1Cs6OtIyzntU$JO05AP%^M@G0!}i z=z;RKy?j#P!8Fh1JADEdQ=rcOq`m*ci{E^&ap$cgF2vrfx?tw)U*`Vsie-6HmP znm>PVRzBpO&95epmQpx8eb(+}d*8bzr{m~$dqxnBDXuoUxn<3{P><7}uJFAAGv$SI z-nsj>#kcQMl=((2d=<9j;XEhjt6zVi=1(z4Af5DPjjuzbkE3ad%%o_0VIP zEkp1pK6VqGzf?dAvSt7DB1d$h&MqP`Hk0dhowb-kjK6`b&L)xnP*7+%%=gKoQ5uIL z&aZH>HbnR(fO(13h`I(ylHHM+DMFmP9-^MyMVQT2#8}LM^C=2e#}+^sAA#=XLX?)| zqmR^(j7QtRGGBvYQ6$_fb|c*V65KD&Lv8yAa#?zi3K$6Rb%%}7cc{+sK}sYOX>23- zKhT5ALsQh&l%T6`6tT8n!1tmOlB2zmAP^wVc?X_~lTj?KM8GMaUJ{13_6`JHo(Z1y za#$Umj%ZUQBn6ryI?NAgUOywkT9ed`5G45;5FJT}-xX4qhI(OVFb6#^svyoU0G;6v ze@A0d`)?uLc_YFc4bTUn2DPQRlw)RqEu*$BuiC-|7;QzLS-(oh(E4R%JG;BK}R(Vm8QnxBQx z%hOOKDS?OaQe+c7EEh+hDE=;-FMkHF+q#Id-GRh=%Tbc)fk!q+ksNvlqQLXW3Nt|* z%Y@Y8VWJy5k;y&`@|e=tx|+DR-qu}31TB%iRONQ zhRPgtb+;qp`uiv;p>hBG8sy|;BZ+AD^8yxxX_-iH+=2vGU9jD*puV{UoU8KS+~15+ zNjloQM-gW^7hG>+m>rl7ze_WSmPJD<3Id-K1Q!EE)R(0r>CQ(;@;r!CH*KWFu~8{4 z0Q<&rjE)T=;@VtD)4kEx--o`g=XlXxJ5k@uE1#peJQ;2ejNx`i9|OIeU>uo)5Mz1N zmk|9-iy)eEfYfahIGJukRYM2bYqF3S`hdJ6aFF7l2|iOBS;9!7=Vvf5JV>;?8-9iq zcn&%c@}3~r&jFdywurJ+M`^wQzW4S_=wW9Q4c3);C@U{VX6$34rzgM%moB;{Z>XhIcczAjy>Kfb8($azu)7hZQN>M>) zBkImtq^11!DkpZv3p#RM?@?xj1)*)E!Zmjg* zyk4%_+Rx)}nwl=Zdw2eKg@G=ElObN;umAYa;u*j1-M;k5#*L*1`u+Fqs#cSYV37Gq zOPxq_F1EWgOM09?=&Potu~OLmXg`+_lRUj<@!KEmx)qx5-K5@pIQ7PfA>ReP)3UWl z945MLyi{gdIVv-XFVt@3Q>^9*@@< z%)a0e%I3SDqiMoZLo1$~{nG50lX)sC0tQX%(-cKJB=1@F%SbLI;Kfet-VJ^oJFWii&>qegwN4QSPyQ5o;^^Oq5v-I);um~6u-8Y;;j1O7s+L`dI#%5h^3WX=$Wbv0{UqtK9YL z_4QRuCbLbIMN|6aMJj~%d8^e%cY~&)qGtWp*(o~}a>`V?dsHkXdZLQd*5T`{RyX~n-o*L4* z|DmDbdV|@j3aJXJme)0{6bSY&0FW^bd&IwyC;tk>A^d!Ni&SYyBTsJvwGo?6zh)=f$KyKV)yI|2 zkw4HmzLT+3@Fy(`NH&`9Qd2WN)rG+LxPxrtW#2cTrzCZ9lJd*{ocRs + + + AT&T Authentication/Authorization Tool + + + +
    +

    AT&T Auth Tool on _ENV_CONTEXT_

    +

    AAF Version: _ARTIFACT_VERSION_

    +
    +

    Success for File Server Access

    + + diff --git a/auth/auth-fs/src/main/java/org/onap/aaf/auth/fs/AAF_FS.java b/auth/auth-fs/src/main/java/org/onap/aaf/auth/fs/AAF_FS.java new file mode 100644 index 00000000..50791393 --- /dev/null +++ b/auth/auth-fs/src/main/java/org/onap/aaf/auth/fs/AAF_FS.java @@ -0,0 +1,115 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.fs; + +import static org.onap.aaf.auth.rserv.HttpMethods.GET; + +import java.io.IOException; + +import javax.servlet.Filter; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.onap.aaf.auth.env.AuthzEnv; +import org.onap.aaf.auth.env.AuthzTrans; +import org.onap.aaf.auth.env.AuthzTransOnlyFilter; +import org.onap.aaf.auth.rserv.CachingFileAccess; +import org.onap.aaf.auth.rserv.HttpCode; +import org.onap.aaf.auth.server.AbsService; +import org.onap.aaf.auth.server.JettyServiceStarter; +import org.onap.aaf.cadi.Access.Level; +import org.onap.aaf.cadi.CadiException; +import org.onap.aaf.cadi.LocatorException; +import org.onap.aaf.cadi.PropAccess; +import org.onap.aaf.cadi.config.Config; +import org.onap.aaf.cadi.register.Registrant; +import org.onap.aaf.cadi.register.RemoteRegistrant; +import org.onap.aaf.misc.env.APIException; + + +public class AAF_FS extends AbsService { + + public AAF_FS(final AuthzEnv env) throws APIException, IOException, CadiException { + super(env.access(),env); + try { + /////////////////////// + // File Server + /////////////////////// + // creates StaticSlot, needed for CachingFileAccess, and sets to public Dir + env.staticSlot(CachingFileAccess.CFA_WEB_PATH,"aaf_public_dir"); + + CachingFileAccess cfa = new CachingFileAccess(env); + route(env,GET,"/:key", cfa); + route(env,GET,"/:key/:cmd", cfa); + final String aaf_locate_url = access.getProperty(Config.AAF_LOCATE_URL, null); + if(aaf_locate_url == null) { + access.printf(Level.WARN, "Redirection requires property %s",Config.AAF_LOCATE_URL); + } else { + route(env,GET,"/", new Redirect(this,aaf_locate_url)); + } + } catch (Exception e) { + e.printStackTrace(); + } + } + + private static class Redirect extends HttpCode { + private final String url; + + public Redirect(AAF_FS context,String url) { + super(context, "Redirect to HTTP/S"); + this.url = url; + } + + @Override + public void handle(AuthzTrans trans, HttpServletRequest req, HttpServletResponse resp) throws Exception { + trans.info().printf("Redirecting %s to HTTP/S %s", req.getRemoteAddr(), req.getLocalAddr()); + resp.sendRedirect(url); + } + }; + + @Override + public Filter[] filters() throws CadiException, LocatorException { + return new Filter[] { + new AuthzTransOnlyFilter(env) + }; + } + + @SuppressWarnings("unchecked") + @Override + public Registrant[] registrants(final int port) throws CadiException, LocatorException { + return new Registrant[] { + new RemoteRegistrant(aafCon(),app_name,app_version,port) + }; + } + + public static void main(final String[] args) { + PropAccess propAccess = new PropAccess(args); + try { + AAF_FS service = new AAF_FS(new AuthzEnv(propAccess)); +// env.setLog4JNames("log4j.properties","authz","fs","audit","init",null); + JettyServiceStarter jss = new JettyServiceStarter(service); + jss.insecure().start(); + } catch (Exception e) { + e.printStackTrace(); + } + } +} diff --git a/auth/auth-fs/src/test/java/org/onap/aaf/auth/fs/test/JU_FileServer.java b/auth/auth-fs/src/test/java/org/onap/aaf/auth/fs/test/JU_FileServer.java new file mode 100644 index 00000000..6e24f6dc --- /dev/null +++ b/auth/auth-fs/src/test/java/org/onap/aaf/auth/fs/test/JU_FileServer.java @@ -0,0 +1,81 @@ +/******************************************************************************* + * ============LICENSE_START==================================================== + * * org.onap.aaf + * * =========================================================================== + * * Copyright © 2017 AT&T Intellectual Property. All rights reserved. + * * =========================================================================== + * * 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==================================================== + * * + * * + ******************************************************************************/ +package org.onap.aaf.auth.fs.test; + +import static org.junit.Assert.*; +import static org.onap.aaf.auth.rserv.HttpMethods.GET; + +import java.io.File; +import java.io.IOException; +import java.net.URL; +import java.util.Properties; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.InjectMocks; +import org.mockito.Matchers; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.runners.MockitoJUnitRunner; +import org.onap.aaf.auth.env.AuthzEnv; +import org.onap.aaf.auth.env.AuthzTrans; +import org.onap.aaf.auth.fs.*; +import org.onap.aaf.auth.rserv.CachingFileAccess; +import org.onap.aaf.misc.env.APIException; +import org.powermock.api.mockito.PowerMockito; +import org.powermock.modules.junit4.PowerMockRunner; + +@RunWith(MockitoJUnitRunner.class) +public class JU_FileServer { + @Mock + AuthzEnv authzEnvMock; + AuthzEnv authzEnv = new AuthzEnv(); + + @Before + public void setUp() throws APIException, IOException{ + + } + + @SuppressWarnings("static-access") + @Test + public void testMain() throws Exception{ + + String[] args = null; + Properties props = new Properties(); + ClassLoader classLoader = getClass().getClassLoader(); + File file = new File(classLoader.getResource("FileServer.props").getFile()); + +//PowerMockito.whenNew(Something.class).withArguments(argument).thenReturn(mockSomething); + // env.setLog4JNames("log4j.properties","authz","fs","audit","init",null); + // PowerMockito.whenNew(AuthzEnv.class).withArguments(props).thenReturn(authzEnvMock); + // PowerMockito.doNothing().when(authzEnvMock.setLog4JNames(Matchers.anyString(), Matchers.anyString(), Matchers.anyString(), Matchers.anyString(), Matchers.anyString(), Matchers.anyString())); + // PowerMockito.when(new AuthzEnv(props)).thenReturn(authzEnvMock); + //PowerMockito.doNothing().when(authzEnv).setLog4JNames(Matchers.anyString(), Matchers.anyString(), Matchers.anyString(), Matchers.anyString(), Matchers.anyString(), Matchers.anyString()); + //PowerMockito.doNothing().when(authzEnvMock).setLog4JNames(" "," "," "," "," "," "); + + AAF_FS.main(args); + //assertTrue(true); + + } + +} diff --git a/auth/auth-gui/.gitignore b/auth/auth-gui/.gitignore new file mode 100644 index 00000000..a95a15c4 --- /dev/null +++ b/auth/auth-gui/.gitignore @@ -0,0 +1,8 @@ +/.settings +/logs +/target +/.classpath +/conf +/bin/ +/tokens/ +/.project diff --git a/auth/auth-gui/pom.xml b/auth/auth-gui/pom.xml new file mode 100644 index 00000000..d2253009 --- /dev/null +++ b/auth/auth-gui/pom.xml @@ -0,0 +1,142 @@ + + + + 4.0.0 + + org.onap.aaf.auth + parent + 2.1.0-SNAPSHOT + ../pom.xml + + + aaf-auth-gui + AAF Auth GUI + GUI Component for AAF Auth Management + + + true + + + + + + org.onap.aaf.auth + aaf-auth-core + + + + org.onap.aaf.auth + aaf-auth-client + + + + org.onap.aaf.auth + aaf-auth-cmd + + + + + org.onap.aaf.auth + aaf-auth-deforg + + + + org.onap.aaf.cadi + aaf-cadi-aaf + + + + org.onap.aaf.cadi + aaf-cadi-client + + + + org.onap.aaf.misc + aaf-misc-xgen + + + + + + + + + + org.apache.maven.plugins + maven-jar-plugin + + + **/*.class + + + 2.3.1 + + + org.apache.maven.plugins + maven-deploy-plugin + + true + + + + org.codehaus.mojo + appassembler-maven-plugin + + + + org.onap.aaf.auth.gui.AAF_GUI + gui + + cadi_prop_files=${project.conf_dir}/org.osaaf.gui.props + + + + -Daaf_cfa_web_path=$BASEDIR/theme/onap + + + + + true + theme + theme + + + + + + + + + nexus + attarch-releases + http://mavencentral.it.att.com:8084/nexus/content/repositories/attarch-releases + + + nexus + attarch-snapshots + http://mavencentral.it.att.com:8084/nexus/content/repositories/attarch-snapshots + + + diff --git a/auth/auth-gui/src/main/config/.gitignore b/auth/auth-gui/src/main/config/.gitignore new file mode 100644 index 00000000..04cdc540 --- /dev/null +++ b/auth/auth-gui/src/main/config/.gitignore @@ -0,0 +1,2 @@ +/authGUI.props +/log4j.properties diff --git a/auth/auth-gui/src/main/java/org/onap/aaf/auth/cui/CUI.java b/auth/auth-gui/src/main/java/org/onap/aaf/auth/cui/CUI.java new file mode 100644 index 00000000..29e36505 --- /dev/null +++ b/auth/auth-gui/src/main/java/org/onap/aaf/auth/cui/CUI.java @@ -0,0 +1,93 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.cui; + +import java.io.PrintWriter; + +import javax.servlet.ServletInputStream; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.onap.aaf.auth.cmd.AAFcli; +import org.onap.aaf.auth.env.AuthzTrans; +import org.onap.aaf.auth.gui.AAF_GUI; +import org.onap.aaf.auth.rserv.HttpCode; +import org.onap.aaf.cadi.aaf.v2_0.AAFConHttp; +import org.onap.aaf.cadi.http.HTransferSS; +import org.onap.aaf.cadi.principal.TaggedPrincipal; +import org.onap.aaf.misc.env.Env; +import org.onap.aaf.misc.env.TimeTaken; + +public class CUI extends HttpCode { + private final AAF_GUI gui; + public CUI(AAF_GUI gui) { + super(null,"Command Line"); + this.gui = gui; + } + + @Override + public void handle(AuthzTrans trans, HttpServletRequest req,HttpServletResponse resp) throws Exception { + ServletInputStream isr = req.getInputStream(); + PrintWriter pw = resp.getWriter(); + int c; + StringBuilder cmd = new StringBuilder(); + + while((c=isr.read())>=0) { + cmd.append((char)c); + } + + TimeTaken tt = trans.start("Execute AAFCLI", Env.REMOTE); + try { + TaggedPrincipal p = trans.getUserPrincipal(); + // Access needs to be set after overall construction. Thus, the lazy create. + AAFcli aafcli; + AAFConHttp aafcon = gui.aafCon(); + aafcli= new AAFcli(gui.access,gui.env, pw, + aafcon.hman(), + aafcon.securityInfo(), + new HTransferSS(p,AAF_GUI.app, + aafcon.securityInfo())); + aafcli.verbose(false); + aafcli.gui(true); + + String cmdStr = cmd.toString(); + if (!cmdStr.contains("--help")) { + cmdStr = cmdStr.replaceAll("help", "--help"); + } + if (!cmdStr.contains("--version")) { + cmdStr = cmdStr.replaceAll("version", "--version"); + } + try { + aafcli.eval(cmdStr); + pw.flush(); + } catch (Exception e) { + pw.flush(); + pw.println(e.getMessage()); + } finally { + aafcli.close(); + } + } finally { + tt.done(); + } + + } +} diff --git a/auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/AAF_GUI.java b/auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/AAF_GUI.java new file mode 100644 index 00000000..be93d63c --- /dev/null +++ b/auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/AAF_GUI.java @@ -0,0 +1,267 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.gui; + +import static org.onap.aaf.auth.rserv.HttpMethods.GET; +import static org.onap.aaf.auth.rserv.HttpMethods.POST; +import static org.onap.aaf.auth.rserv.HttpMethods.PUT; + +import javax.servlet.Filter; + +import org.onap.aaf.auth.cmd.Cmd; +import org.onap.aaf.auth.cui.CUI; +import org.onap.aaf.auth.env.AuthzEnv; +import org.onap.aaf.auth.env.AuthzTrans; +import org.onap.aaf.auth.env.AuthzTransFilter; +import org.onap.aaf.auth.gui.pages.ApiDocs; +import org.onap.aaf.auth.gui.pages.ApiExample; +import org.onap.aaf.auth.gui.pages.ApprovalAction; +import org.onap.aaf.auth.gui.pages.ApprovalForm; +import org.onap.aaf.auth.gui.pages.CMArtiChangeAction; +import org.onap.aaf.auth.gui.pages.CMArtiChangeForm; +import org.onap.aaf.auth.gui.pages.CMArtifactShow; +import org.onap.aaf.auth.gui.pages.CredDetail; +import org.onap.aaf.auth.gui.pages.Home; +import org.onap.aaf.auth.gui.pages.LoginLanding; +import org.onap.aaf.auth.gui.pages.LoginLandingAction; +import org.onap.aaf.auth.gui.pages.NsDetail; +import org.onap.aaf.auth.gui.pages.NsHistory; +import org.onap.aaf.auth.gui.pages.NsInfoAction; +import org.onap.aaf.auth.gui.pages.NsInfoForm; +import org.onap.aaf.auth.gui.pages.NssShow; +import org.onap.aaf.auth.gui.pages.PassChangeAction; +import org.onap.aaf.auth.gui.pages.PassChangeForm; +import org.onap.aaf.auth.gui.pages.PassDeleteAction; +import org.onap.aaf.auth.gui.pages.PendingRequestsShow; +import org.onap.aaf.auth.gui.pages.PermDetail; +import org.onap.aaf.auth.gui.pages.PermGrantAction; +import org.onap.aaf.auth.gui.pages.PermGrantForm; +import org.onap.aaf.auth.gui.pages.PermHistory; +import org.onap.aaf.auth.gui.pages.PermsShow; +import org.onap.aaf.auth.gui.pages.RequestDetail; +import org.onap.aaf.auth.gui.pages.RoleDetail; +import org.onap.aaf.auth.gui.pages.RoleDetailAction; +import org.onap.aaf.auth.gui.pages.RoleHistory; +import org.onap.aaf.auth.gui.pages.RolesShow; +import org.onap.aaf.auth.gui.pages.UserRoleExtend; +import org.onap.aaf.auth.gui.pages.UserRoleRemove; +import org.onap.aaf.auth.gui.pages.WebCommand; +import org.onap.aaf.auth.rserv.CachingFileAccess; +import org.onap.aaf.auth.server.AbsService; +import org.onap.aaf.auth.server.JettyServiceStarter; +import org.onap.aaf.cadi.CadiException; +import org.onap.aaf.cadi.LocatorException; +import org.onap.aaf.cadi.PropAccess; +import org.onap.aaf.cadi.aaf.v2_0.AAFConHttp; +import org.onap.aaf.cadi.aaf.v2_0.AAFLurPerm; +import org.onap.aaf.cadi.aaf.v2_0.AAFTrustChecker; +import org.onap.aaf.cadi.client.Future; +import org.onap.aaf.cadi.client.Retryable; +import org.onap.aaf.cadi.config.Config; +import org.onap.aaf.cadi.http.HTransferSS; +import org.onap.aaf.cadi.principal.TaggedPrincipal; +import org.onap.aaf.cadi.register.Registrant; +import org.onap.aaf.cadi.register.RemoteRegistrant; +import org.onap.aaf.misc.env.APIException; +import org.onap.aaf.misc.env.Env; +import org.onap.aaf.misc.env.Slot; +import org.onap.aaf.misc.env.StaticSlot; +import org.onap.aaf.misc.env.util.Split; +import org.onap.aaf.misc.rosetta.env.RosettaDF; +import org.onap.aaf.misc.xgen.html.HTMLGen; +import org.onap.aaf.misc.xgen.html.State; + +import certman.v1_0.Artifacts; +import certman.v1_0.CertInfo; + +public class AAF_GUI extends AbsService implements State{ + private static final String AAF_GUI_THEME = "aaf_gui_theme"; + public static final String AAF_GUI_COPYRIGHT = "aaf_gui_copyright"; + public static final String HTTP_SERVLET_REQUEST = "HTTP_SERVLET_REQUEST"; + public static final int TIMEOUT = 60000; + public static final String app = "AAF GUI"; + + // AAF API + + // Certificate manager API + public RosettaDF artifactsDF; + public RosettaDF certInfoDF; + + private final AAFConHttp cmCon; + public final AAFConHttp aafCon; + public final AAFLurPerm lur; + + public final Slot slot_httpServletRequest; + protected final String deployedVersion; + private StaticSlot sTheme; + public final String theme; + + + public AAF_GUI(final AuthzEnv env) throws Exception { + super(env.access(), env); + sTheme = env.staticSlot(CachingFileAccess.CFA_WEB_PATH,access.getProperty(CachingFileAccess.CFA_WEB_PATH,null)==null?AAF_GUI_THEME:CachingFileAccess.CFA_WEB_PATH); + theme = env.getProperty(AAF_GUI_THEME); + + //OrganizationFactory.setDefaultOrg(env, "org.osaaf.authz.org.att.ATT"); + + slot_httpServletRequest = env.slot(HTTP_SERVLET_REQUEST); + String[] component = Split.split(':', access.getProperty(Config.AAF_COMPONENT, "N/A:2.x")); + if(component.length>1) { + deployedVersion =component[1]; + } else { + deployedVersion = "2.x"; + } + + // Certificate Manager + cmCon = new AAFConHttp(env.access(),Config.CM_URL); + artifactsDF = env.newDataFactory(Artifacts.class); + certInfoDF = env.newDataFactory(CertInfo.class); + + + ///////////////////////// + // Screens + ///////////////////////// + // Start Screen + final Page start = new Display(this, GET, new Home(this)).page(); + + // MyPerms Screens + final Page myPerms = new Display(this, GET, new PermsShow(this, start)).page(); + Page permDetail = new Display(this, GET, new PermDetail(this, start, myPerms)).page(); + new Display(this, GET, new PermHistory(this,start,myPerms,permDetail)); + + // MyRoles Screens + final Page myRoles = new Display(this, GET, new RolesShow(this, start)).page(); + Page roleDetail = new Display(this, GET, new RoleDetail(this, start, myRoles)).page(); + new Display(this, POST, new RoleDetailAction(this,start,myRoles,roleDetail)); + new Display(this, GET, new RoleHistory(this,start,myRoles,roleDetail)); + + // MyNameSpace + final Page myNamespaces = new Display(this, GET, new NssShow(this, start)).page(); + Page nsDetail = new Display(this, GET, new NsDetail(this, start, myNamespaces)).page(); + new Display(this, GET, new NsHistory(this, start,myNamespaces,nsDetail)); + Page crdDetail = new Display(this, GET, new CredDetail(this, start, myNamespaces, nsDetail)).page(); + Page artiShow = new Display(this, GET, new CMArtifactShow(this, start, myNamespaces, nsDetail, crdDetail)).page(); + Page artiCForm = new Display(this, GET, new CMArtiChangeForm(this, start, myNamespaces, nsDetail, crdDetail,artiShow)).page(); + new Display(this, POST, new CMArtiChangeAction(this, start,artiShow,artiCForm)); + + // Password Change Screens + final Page pwc = new Display(this, GET, new PassChangeForm(this, start,crdDetail)).page(); + new Display(this, POST, new PassChangeAction(this, start, pwc)); + + // Password Delete Screen + new Display(this, GET, new PassDeleteAction(this, start,crdDetail)); + + // Validation Change Screens + final Page validate = new Display(this, GET, new ApprovalForm(this, start)).page(); + new Display(this, POST, new ApprovalAction(this, start, validate)); + + // Onboard, Detailed Edit Screens + final Page onb = new Display(this, GET, new NsInfoForm(this, start)).page(); + new Display(this, POST, new NsInfoAction(this, start, onb)); + + // Web Command Screens + /* final Page webCommand =*/ new Display(this, GET, new WebCommand(this, start)).page(); + + // API Docs + final Page apidocs = new Display(this, GET, new ApiDocs(this, start)).page(); + new Display(this, GET, new ApiExample(this,start, apidocs)).page(); + + // Permission Grant Page + final Page permGrant = new Display(this, GET, new PermGrantForm(this, start)).page(); + new Display(this, POST, new PermGrantAction(this, start, permGrant)).page(); + + // Login Landing if no credentials detected + final Page loginLanding = new Display(this, GET, new LoginLanding(this, start)).page(); + new Display(this, POST, new LoginLandingAction(this, start, loginLanding)); + + // User Role Request Extend and Remove + new Display(this, GET, new UserRoleExtend(this, start,myRoles)).page(); + new Display(this, GET, new UserRoleRemove(this, start,myRoles)).page(); + + // See my Pending Requests + final Page requestsShow = new Display(this, GET, new PendingRequestsShow(this, start)).page(); + new Display(this, GET, new RequestDetail(this, start, requestsShow)); + + // Command line Mechanism + route(env, PUT, "/gui/cui", new CUI(this),"text/plain;charset=utf-8","*/*"); + + /////////////////////// + // WebContent Handler + /////////////////////// + route(env,GET,"/"+env.get(sTheme)+"/:key", new CachingFileAccess(env)); + /////////////////////// + aafCon = aafCon(); + lur = aafCon.newLur(); + } + + public RosettaDF getDF(Class cls) throws APIException { + return Cmd.getDF(env,cls); + } + + public void writeError(AuthzTrans trans, Future fp, HTMLGen hgen, int indent) { + if(hgen!=null) { + String msg = aafCon.readableErrMsg(fp); + hgen.incr(HTMLGen.P,"style=text-indent:"+indent*10+"px") + .text("Error: ") + .text(msg) + .end(); + trans.checkpoint(msg); + } + } + + public RET cmClientAsUser(TaggedPrincipal p,Retryable retryable) throws APIException, LocatorException, CadiException { + return cmCon.hman().best(new HTransferSS(p,app, aafCon.securityInfo()), retryable); + } + @Override + public Filter[] filters() throws CadiException, LocatorException { + try { + return new Filter[] { + new XFrameFilter(XFrameFilter.TYPE.none), + new AuthzTransFilter(env,aafCon(), + new AAFTrustChecker((Env)env)), + new OrgLookupFilter() + }; + } catch (NumberFormatException e) { + throw new CadiException("Invalid Property information", e); + } + } + + @SuppressWarnings("unchecked") + @Override + public Registrant[] registrants(final int port) throws CadiException, LocatorException { + return new Registrant[] { + new RemoteRegistrant(aafCon(),app_name,app_version,port) + }; + } + + public static void main(final String[] args) { + PropAccess propAccess = new PropAccess(args); + try { + AAF_GUI service = new AAF_GUI(new AuthzEnv(propAccess)); +// env.setLog4JNames("log4j.properties","authz","gui","audit","init","trace "); + JettyServiceStarter jss = new JettyServiceStarter(service); + jss.start(); + } catch (Exception e) { + e.printStackTrace(); + } + } +} diff --git a/auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/BreadCrumbs.java b/auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/BreadCrumbs.java new file mode 100644 index 00000000..4602184f --- /dev/null +++ b/auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/BreadCrumbs.java @@ -0,0 +1,90 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.gui; + +import static org.onap.aaf.misc.xgen.html.HTMLGen.A; +import static org.onap.aaf.misc.xgen.html.HTMLGen.LI; +import static org.onap.aaf.misc.xgen.html.HTMLGen.UL; + +import java.io.IOException; + +import javax.servlet.http.HttpServletRequest; + +import org.onap.aaf.misc.env.APIException; +import org.onap.aaf.misc.env.TransStore; +import org.onap.aaf.misc.xgen.Cache; +import org.onap.aaf.misc.xgen.DynamicCode; +import org.onap.aaf.misc.xgen.Mark; +import org.onap.aaf.misc.xgen.html.HTMLGen; + +public class BreadCrumbs extends NamedCode { + private Page[] breadcrumbs; + + public BreadCrumbs(Page ... pages) { + super(false,"breadcrumbs"); + breadcrumbs = pages; + } + + @Override + public void code(final Cache cache, final HTMLGen hgen) throws APIException, IOException { + // BreadCrumbs + Mark mark = new Mark(); + hgen.incr(mark, UL); + cache.dynamic(hgen, new DynamicCode() { + @Override + public void code(AAF_GUI gui, TransStore trans, final Cache cache, final HTMLGen hgen) throws APIException, IOException { + HttpServletRequest req = trans.get(gui.slot_httpServletRequest, null); + StringBuilder key = new StringBuilder(); + String value, hidden; + for(Page p : breadcrumbs) { + hidden=""; + // Add keys for page from commandline, where possible. + if(p.fields().length>0) { + boolean first = true; + key.setLength(0); + for(String field : p.fields()) { + if((value=req.getParameter(field))==null) { + hidden="style=display:none;"; + break; + } + if(first) { + first = false; + key.append('?'); + } else { + key.append("&"); + } + key.append(field); + key.append('='); + key.append(value); + } + hgen.incr(LI,true,hidden); + hgen.leaf(A,"href="+p.url()+key.toString(),hidden).text(p.name()).end(2); + } else { + hgen.incr(LI,true); + hgen.leaf(A,"href="+p.url(),hidden).text(p.name()).end(2); + } + } + } + }); + hgen.end(mark); + } +} diff --git a/auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/ContentCode.java b/auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/ContentCode.java new file mode 100644 index 00000000..d3c24dc2 --- /dev/null +++ b/auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/ContentCode.java @@ -0,0 +1,36 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.gui; + +import org.onap.aaf.misc.xgen.Code; +import org.onap.aaf.misc.xgen.html.HTMLGen; + +/** + * Interface for which Page, etc can get Attributes, determine whether cached, etc + * @author Jonathan + * + */ +public interface ContentCode extends Code { + public String[] idattrs(); + public void addAttr(boolean first, String attr); + public boolean no_cache(); +} diff --git a/auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/Controls.java b/auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/Controls.java new file mode 100644 index 00000000..5b582f38 --- /dev/null +++ b/auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/Controls.java @@ -0,0 +1,45 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.gui; + +import java.io.IOException; + +import org.onap.aaf.misc.env.APIException; +import org.onap.aaf.misc.xgen.Cache; +import org.onap.aaf.misc.xgen.html.HTMLGen; + +public class Controls extends NamedCode { + public Controls() { + super(false,"controls"); + } + + @Override + public void code(final Cache cache, final HTMLGen hgen) throws APIException, IOException { + hgen.incr("form","method=post") + .incr("input", true, "type=checkbox", "name=vehicle", "value=Bike").text("I have a bike").end() + .text("Password: ") + .incr("input", true, "type=password", "id=password1").end() + .tagOnly("input", "type=submit", "value=Submit") + .end(); + } + +} diff --git a/auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/Display.java b/auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/Display.java new file mode 100644 index 00000000..ad43d3fb --- /dev/null +++ b/auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/Display.java @@ -0,0 +1,140 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.gui; + +import java.util.Enumeration; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.onap.aaf.auth.env.AuthzTrans; +import org.onap.aaf.auth.rserv.HttpCode; +import org.onap.aaf.auth.rserv.HttpMethods; +import org.onap.aaf.misc.env.Slot; + +public class Display { + private final Page get; + public Display(final AAF_GUI gui, final HttpMethods meth, final Page page) { + get = page; + final String[] fields = page.fields(); + final Slot slots[] = new Slot[fields.length]; + String prefix = page.name() + '.'; + for(int i=0;i(gui,page.name()) { + @Override + public void handle(AuthzTrans trans, HttpServletRequest req, HttpServletResponse resp) throws Exception { + trans.put(gui.slot_httpServletRequest, req); + for(int i=0; i" corresponding to an array of types + String field=fields[i].substring(0, idx)+'.'; + String[] array = new String[16]; + for(Enumeration names = req.getParameterNames(); names.hasMoreElements();) { + String key = names.nextElement(); + if(key.startsWith(field)) { + try { + int x = Integer.parseInt(key.substring(field.length())); + if(x>=array.length) { + String[] temp = new String[x+10]; + System.arraycopy(temp, 0, temp, 0, array.length); + array = temp; + } + array[x]=req.getParameter(key); + } catch (NumberFormatException e) { + trans.debug().log(e); + } + } + } + trans.put(slots[i], array); + } + } + page.replay(context,trans,resp.getOutputStream(),"general"); + } + }, "application/x-www-form-urlencoded","*/*"); + + } else { + // Transfer whether Page shouldn't be cached to local Final var. + final boolean no_cache = page.no_cache; + + gui.route(gui.env, meth, page.url(), + new HttpCode(gui,page.name()) { + @Override + public void handle(AuthzTrans trans, HttpServletRequest req, HttpServletResponse resp) throws Exception { + trans.put(gui.slot_httpServletRequest, req); + for(int i=0; i mm = req.getParameterNames();mm.hasMoreElements();) { + String key = mm.nextElement(); + if(key.startsWith(field)) { + try { + int x = Integer.parseInt(key.substring(field.length())); + if(x>=array.length) { + String[] temp = new String[x+10]; + System.arraycopy(temp, 0, temp, 0, array.length); + array = temp; + } + array[x]=req.getParameter(key); + } catch (NumberFormatException e) { + trans.debug().log(e); + } + } + } + trans.put(slots[i], array); + } + } + page.replay(context,trans,resp.getOutputStream(),"general"); + } + + @Override + public boolean no_cache() { + return no_cache; + } + }, "text/html","*/*"); + } + + } + + public Page page() { + return get; + } +} \ No newline at end of file diff --git a/auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/Form.java b/auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/Form.java new file mode 100644 index 00000000..7011395c --- /dev/null +++ b/auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/Form.java @@ -0,0 +1,68 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.gui; + +import java.io.IOException; + +import org.onap.aaf.misc.env.APIException; +import org.onap.aaf.misc.xgen.Cache; +import org.onap.aaf.misc.xgen.html.HTMLGen; + +public class Form extends NamedCode { + private String preamble; + private NamedCode content; + + public Form(boolean no_cache, NamedCode content) { + super(no_cache,content); + this.content = content; + preamble=null; + } + + public Form preamble(String preamble) { + this.preamble = preamble; + return this; + } + + + @Override + public void code(final Cache cache, final HTMLGen hgen) throws APIException, IOException { + if(preamble!=null) { + hgen.incr("p","class=preamble").text(preamble).end(); + } + hgen.incr("form","method=post"); + + content.code(cache, hgen); + + hgen.tagOnly("input", "type=submit", "value=Submit") + .tagOnly("input", "type=reset", "value=Reset") + .end(); + } + + /* (non-Javadoc) + * @see org.onap.aaf.auth.gui.NamedCode#idattrs() + */ + @Override + public String[] idattrs() { + return content.idattrs(); + } + +} diff --git a/auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/NamedCode.java b/auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/NamedCode.java new file mode 100644 index 00000000..e4bd6c7d --- /dev/null +++ b/auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/NamedCode.java @@ -0,0 +1,67 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.gui; + +public abstract class NamedCode implements ContentCode { + private final boolean no_cache; + private String name; + private String[] idattrs; + + /* + * Mark whether this code should not be cached, and any attributes + */ + public NamedCode(final boolean no_cache, final String name) { + this.name = name; + idattrs = new String[] {name}; + this.no_cache = no_cache; + } + + public NamedCode(boolean no_cache, NamedCode content) { + this.no_cache = no_cache; + name=content.name; + idattrs = content.idattrs; + } + + /** + * Return ID and Any Attributes needed to create a "div" section of this code + * @return + */ + public String[] idattrs() { + return idattrs; + } + + public void addAttr(boolean first, String attr) { + String[] temp = new String[idattrs.length+1]; + if(first) { + temp[0] = attr; + System.arraycopy(idattrs, 0, temp, 1, idattrs.length); + } else { + temp[idattrs.length] = attr; + System.arraycopy(idattrs, 0, temp, 0, idattrs.length); + } + idattrs = temp; + } + + public boolean no_cache() { + return no_cache; + } +} diff --git a/auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/OrgLookupFilter.java b/auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/OrgLookupFilter.java new file mode 100644 index 00000000..411ecdb8 --- /dev/null +++ b/auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/OrgLookupFilter.java @@ -0,0 +1,58 @@ +package org.onap.aaf.auth.gui; + +import java.io.IOException; +import java.security.Principal; + +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 org.onap.aaf.auth.env.AuthzTrans; +import org.onap.aaf.auth.org.OrganizationException; +import org.onap.aaf.auth.org.Organization.Identity; +import org.onap.aaf.auth.rserv.TransFilter; +import org.onap.aaf.cadi.CadiException; +import org.onap.aaf.cadi.principal.TaggedPrincipal; + +public class OrgLookupFilter implements Filter { + + @Override + public void init(FilterConfig arg0) throws ServletException { + } + + @Override + public void doFilter(ServletRequest req, ServletResponse resp, FilterChain fc) throws IOException, ServletException { + final AuthzTrans trans = (AuthzTrans) req.getAttribute(TransFilter.TRANS_TAG); + if(req instanceof HttpServletRequest) { + Principal p = ((HttpServletRequest)req).getUserPrincipal(); + if(p instanceof TaggedPrincipal) { + ((TaggedPrincipal)p).setTagLookup(new TaggedPrincipal.TagLookup() { + @Override + public String lookup() throws CadiException { + Identity id; + try { + id = trans.org().getIdentity(trans, p.getName()); + if(id.isFound()) { + return id.firstName(); + } + } catch (OrganizationException e) { + throw new CadiException(e); + } + return p.getName(); + } + }); + } + fc.doFilter(req, resp); + } + + } + + + @Override + public void destroy() { + } +} diff --git a/auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/Page.java b/auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/Page.java new file mode 100644 index 00000000..436b37a0 --- /dev/null +++ b/auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/Page.java @@ -0,0 +1,402 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.gui; + +import static org.onap.aaf.misc.xgen.html.HTMLGen.A; +import static org.onap.aaf.misc.xgen.html.HTMLGen.H1; +import static org.onap.aaf.misc.xgen.html.HTMLGen.LI; +import static org.onap.aaf.misc.xgen.html.HTMLGen.TITLE; +import static org.onap.aaf.misc.xgen.html.HTMLGen.UL; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; + +import javax.servlet.http.HttpServletRequest; + +import org.onap.aaf.auth.common.Define; +import org.onap.aaf.auth.env.AuthzEnv; +import org.onap.aaf.auth.env.AuthzTrans; +import org.onap.aaf.auth.rserv.CachingFileAccess; +import org.onap.aaf.cadi.Permission; +import org.onap.aaf.cadi.aaf.AAFPermission; +import org.onap.aaf.cadi.config.Config; +import org.onap.aaf.cadi.principal.TaggedPrincipal; +import org.onap.aaf.misc.env.APIException; +import org.onap.aaf.misc.env.Slot; +import org.onap.aaf.misc.env.StaticSlot; +import org.onap.aaf.misc.env.util.Split; +import org.onap.aaf.misc.xgen.Cache; +import org.onap.aaf.misc.xgen.CacheGen; +import org.onap.aaf.misc.xgen.Code; +import org.onap.aaf.misc.xgen.DynamicCode; +import org.onap.aaf.misc.xgen.Mark; +import org.onap.aaf.misc.xgen.html.HTMLCacheGen; +import org.onap.aaf.misc.xgen.html.HTMLGen; +import org.onap.aaf.misc.xgen.html.Imports; + +/** + * A Base "Mobile First" Page + * + * @author Jonathan + * + */ +public class Page extends HTMLCacheGen { + public static final String AAFURL_TOOLS = "aaf_url.tools"; + public static final String AAF_URL_TOOL_DOT = "aaf_url.tool."; + public static final String AAF_URL_CUIGUI = "aaf_url.cuigui"; // link to help + public static final String AAF_URL_GUI_ONBOARD = "aaf_url.gui_onboard"; + public static final String AAF_URL_AAF_HELP = "aaf_url.aaf_help"; + public static final String AAF_URL_CADI_HELP = "aaf_url.cadi_help"; + public static final String PERM_CA_TYPE = Define.ROOT_NS() + ".ca"; + + public static enum BROWSER {iPhone,html5,ie,ieOld}; + + public static final int MAX_LINE=20; + + protected static final String[] NO_FIELDS = new String[0]; + + private static final String BROWSER_TYPE = "BROWSER_TYPE"; + + private final String bcName, bcUrl; + private final String[] fields; + + public final boolean no_cache; + + // Note: Only access is synchronized in "getPerm" + private final static Map> perms = new HashMap>(); + + public String name() { + return bcName; + } + + public String url() { + return bcUrl; + } + + public String[] fields() { + return fields; + } + + public Page(AuthzEnv env, String name, String url, Enum[] en, final NamedCode ...content) throws APIException, IOException { + super(CacheGen.PRETTY, new PageCode(env, 1, content)); + fields = new String[en.length]; + int i=-1; + for(Enum p : en) { + fields[++i]=p.name(); + } + + bcName = name; + bcUrl = url; + // Mark which fields must be "no_cache" + boolean no_cacheTemp=false; + for(NamedCode nc : content) { + if(nc.no_cache()) { + no_cacheTemp=true; + break; + } + } + no_cache=no_cacheTemp; + } + public Page(AuthzEnv env, String name, String url, String [] fields, final NamedCode ... content) throws APIException,IOException { + this(env,name,url,1,fields,content); + } + + public Page(AuthzEnv env, String name, String url, int backdots, String [] fields, final NamedCode ... content) throws APIException,IOException { + super(CacheGen.PRETTY, new PageCode(env, backdots, content)); + if(fields==null) { + this.fields = new String[0]; + } else { + this.fields = fields; + } + bcName = name; + bcUrl = url; + // Mark which fields must be "no_cache" + boolean no_cacheTemp=false; + for(NamedCode nc : content) { + if(nc.no_cache()) { + no_cacheTemp=true; + break; + } + } + no_cache=no_cacheTemp; + } + + + private static class PageCode implements Code { + private static final String AAF_GUI_TITLE = "aaf_gui_title"; + + private final ContentCode[] content; + private final Slot browserSlot; + private final int backdots; + protected AuthzEnv env; + private StaticSlot sTheme; + + public PageCode(AuthzEnv env, int backdots, final ContentCode[] content) { + this.content = content; + this.backdots = backdots; + browserSlot = env.slot(BROWSER_TYPE); + sTheme = env.staticSlot(CachingFileAccess.CFA_WEB_PATH); + this.env = env; + } + + @Override + public void code(final Cache cache, final HTMLGen hgen) throws APIException, IOException { + // Note: I found that App Storage saves everything about the page, or not. Thus, if you declare the page uncacheable, none of the + // Artifacts, like JPGs are stored, which makes this feature useless for Server driven elements + cache.dynamic(hgen, new DynamicCode() { + @Override + public void code(AAF_GUI state, AuthzTrans trans, final Cache cache, final HTMLGen hgen) throws APIException, IOException { + switch(browser(trans,browserSlot)) { + case ieOld: + case ie: + hgen.directive("!DOCTYPE html"); + hgen.directive("meta", "http-equiv=X-UA-Compatible","content=IE=11"); + default: + } + } + }); + hgen.html(); + final String title = env.getProperty(AAF_GUI_TITLE,"Authentication/Authorization Framework"); + final String theme = env.get(sTheme); + Mark head = hgen.head(); + hgen.leaf(TITLE).text(title).end(); + hgen.imports(new Imports(backdots).css(theme + "/aaf5.css") + .js(theme + "/comm.js") + .js(theme + "/console.js") + .js(theme + "/common.js")); + cache.dynamic(hgen, new DynamicCode() { + @Override + public void code(AAF_GUI state, AuthzTrans trans, final Cache cache, final HTMLGen hgen) throws APIException, IOException { + switch(browser(trans,browserSlot)) { + case iPhone: + hgen.imports(new Imports(backdots).css(theme + "/aaf5iPhone.css")); + break; + case ie: + case ieOld: + hgen.js().text("document.createElement('header');") + .text("document.createElement('nav');") + .done(); + case html5: + hgen.imports(new Imports(backdots).css(theme + "/aaf5Desktop.css")); + break; + } + } + }); + hgen.end(head); + + Mark body = hgen.body(); + Mark header = hgen.header(); + cache.dynamic(hgen, new DynamicCode() { + @Override + public void code(AAF_GUI state, AuthzTrans trans,Cache cache, HTMLGen xgen) + throws APIException, IOException { + // Obtain Server Info, and print + // AT&T Only + String env = trans.getProperty(Config.AAF_ENV,"N/A"); + xgen.leaf(H1).text(title + " on " + env).end(); + xgen.leaf("p","id=version").text("AAF Version: " + state.deployedVersion).end(); + + // Obtain User Info, and print + TaggedPrincipal p = trans.getUserPrincipal(); + String user,secured; + if(p==null) { + user = "please choose a Login Authority"; + secured = "NOT Secure!"; + } else { + user = p.personalName(); + secured = p.tag(); + } + xgen.leaf("p","id=welcome").text("Welcome, ") + .text(user) + .text("") + .text(secured) + .text("").end(); + + switch(browser(trans,browserSlot)) { + case ieOld: + case ie: + xgen.incr("h5").text("This app is Mobile First HTML5. Internet Explorer " + + " does not support all HTML5 standards. Old, non TSS-Standard versions may not function correctly.").br() + .text(" For best results, use a highly compliant HTML5 browser like Firefox.") + .end(); + break; + default: + } + } + }); + + hgen.hr(); + + int cIdx; + ContentCode nc; + // If BreadCrumbs, put here + if(content.length>0 && content[0] instanceof BreadCrumbs) { + nc = content[0]; + Mark ctnt = hgen.divID(nc.idattrs()); + nc.code(cache, hgen); + hgen.end(ctnt); + cIdx = 1; + } else { + cIdx = 0; + } + + hgen.end(header); + + Mark inner = hgen.divID("inner"); + // Content + for(int i=cIdx;i=0 + * + * Use int found in "ieVersion" + * + * Official IE 7 + * Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; .NET CLR 1.1.4322; + * .NET CLR 2.0.50727; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729) + * Official IE 8 + * Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; WOW64; Trident/4.0; SLCC2; + * .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; .NET4.0E; ATT) + * + * IE 11 Compatibility + * Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; SLCC2; .NET CLR 2.0.50727; + * .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET CLR 1.1.4322; .NET4.0C; .NET4.0E; InfoPath.3; HVD; ATT) + * + * IE 11 (not Compatiblity) + * Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; Trident/4.0; SLCC2; .NET CLR 2.0.50727; + * .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET CLR 1.1.4322; .NET4.0C; .NET4.0E; InfoPath.3; HVD; ATT) + * + * @param trans + * @return + */ + public static BROWSER browser(AuthzTrans trans, Slot slot) { + BROWSER br = trans.get(slot, null); + if(br==null) { + String agent = trans.agent(); + int msie; + if(agent.contains("iPhone") /* other phones? */) { + br=BROWSER.iPhone; + } else if ((msie = agent.indexOf("MSIE"))>=0) { + msie+=5; + int end = agent.indexOf(";",msie); + float ver; + try { + ver = Float.valueOf(agent.substring(msie,end)); + br = ver<8f?BROWSER.ieOld:BROWSER.ie; + } catch (Exception e) { + br = BROWSER.ie; + } + } else { + br = BROWSER.html5; + } + trans.put(slot,br); + } + return br; + } + + /* + * Get, rather than create each time, permissions for validations + */ + protected static synchronized Permission getPerm(String instance, String action) { + Map msp = perms.get(instance); + Permission p; + if(msp==null) { + msp = new HashMap(); + perms.put(instance, msp); + p=null; + } else { + p = msp.get(instance); + } + if(p==null) { + p=new AAFPermission(PERM_CA_TYPE,instance,action); + msp.put(action, p); + } + return p; + } + + protected static String getSingleParam(HttpServletRequest req, String tag) { + String values[] = req.getParameterValues(tag); + return values.length<1?null:values[0]; + } + + +} + diff --git a/auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/SlotCode.java b/auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/SlotCode.java new file mode 100644 index 00000000..b457fc9b --- /dev/null +++ b/auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/SlotCode.java @@ -0,0 +1,49 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.gui; + +import org.onap.aaf.misc.env.EnvStore; +import org.onap.aaf.misc.env.Slot; +import org.onap.aaf.misc.env.TransStore; + +public abstract class SlotCode extends NamedCode { + private Slot[] slots; + + public SlotCode(boolean no_cache,EnvStore env, String root, Enum ... params) { + super(no_cache,root); + slots = new Slot[params.length]; + for(int i=0;i T get(TRANS trans,Enum en, T dflt) { + return get(trans,en.ordinal(),dflt); + } + + public T get(TRANS trans,int idx, T dflt) { + if(idx>slots.length) { + return dflt; + } + return trans.get(slots[idx],dflt); + } +} diff --git a/auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/Table.java b/auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/Table.java new file mode 100644 index 00000000..6839a9ab --- /dev/null +++ b/auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/Table.java @@ -0,0 +1,229 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.gui; + +import static org.onap.aaf.misc.xgen.html.HTMLGen.TABLE; +import static org.onap.aaf.misc.xgen.html.HTMLGen.TD; +import static org.onap.aaf.misc.xgen.html.HTMLGen.TR; + +import java.io.IOException; +import java.util.ArrayList; + +import org.onap.aaf.auth.gui.table.AbsCell; +import org.onap.aaf.misc.env.APIException; +import org.onap.aaf.misc.env.Env; +import org.onap.aaf.misc.env.Slot; +import org.onap.aaf.misc.env.Trans; +import org.onap.aaf.misc.env.TransStore; +import org.onap.aaf.misc.xgen.Cache; +import org.onap.aaf.misc.xgen.Code; +import org.onap.aaf.misc.xgen.DynamicCode; +import org.onap.aaf.misc.xgen.Mark; +import org.onap.aaf.misc.xgen.html.HTMLGen; +import org.onap.aaf.misc.xgen.html.State; + +public class Table, TRANS extends TransStore> extends NamedCode { + private final Slot ROW_MSG_SLOT, EMPTY_TABLE_SLOT; + private final String title; + private final String[] columns; + private final Rows rows; + private Code other; +// private DynamicCode prefix,postfix; + + public Table(String title, TRANS trans, Data data, Code other, String name, String ... attrs) { + this(title,trans,data,name, attrs); + this.other = other; + } + + public Table(String title, TRANS trans, Data data, String name, String ... attrs) { + super(true,name); +// prefix=postfix=null; + for(String a : attrs) { + addAttr(false, a); + } + ROW_MSG_SLOT=trans.slot("TABLE_ROW_MSG"); + EMPTY_TABLE_SLOT=trans.slot("TABLE_EMPTY"); + this.columns = data.headers(); + boolean alt = false; + for(String s : attrs) { + if("class=std".equals(s) || "class=stdform".equals(s)) { + alt=true; + } + } + rows = new Rows(data,alt?1:0); + this.title = title; + // Derive an ID from title (from no spaces, etc), and prepend to IDAttributes (Protected from NamedCode) + addAttr(true,title(trans).replaceAll("\\s","")); + + other = null; + } + + @Override + public void code(final Cache cache, final HTMLGen hgen) throws APIException, IOException { + cache.dynamic(hgen, new DynamicCode() { + @Override + public void code(S state, TRANS trans, Cache cache, HTMLGen xgen) throws APIException, IOException { + rows.data.prefix(state, trans, cache, xgen); + } + }); + Mark table = new Mark(); + Mark tr = new Mark(); + + hgen.incr(table,TABLE); + if(title==null) { + cache.dynamic(hgen, new DynamicCode() { + @Override + public void code(S state, TRANS trans, final Cache cache, final HTMLGen hgen) throws APIException, IOException { + hgen.leaf("caption", "class=title").text(title(trans)).end(); + } + }); + } else { + hgen.leaf("caption", "class=title").text(title).end(); + } + hgen.incr(tr,TR); + for(String column : columns) { + hgen.leaf("th").text(column).end(); + } + hgen.end(tr); + + // Load Rows Dynamically + cache.dynamic(hgen, rows); + // End Table + hgen.end(table); + + if(other!=null) { + other.code(cache,hgen); + } + + // Print Message from Row Gathering, if available + cache.dynamic(hgen, new DynamicCode() { + @Override + public void code(S state, TRANS trans, final Cache cache, final HTMLGen hgen) throws APIException, IOException { + String msg; + if((msg = trans.get(EMPTY_TABLE_SLOT, null))!=null) { + hgen.incr("style").text("#inner tr,caption,input,p.preamble {display: none;}#inner p.notfound {margin: 0px 0px 0px 20px}").end(); + hgen.incr(HTMLGen.P,"class=notfound").text(msg).end().br(); + } else if((msg=trans.get(ROW_MSG_SLOT,null))!=null) { + hgen.p(msg).br(); + } + } + }); + cache.dynamic(hgen, new DynamicCode() { + @Override + public void code(S state, TRANS trans, Cache cache, HTMLGen xgen) throws APIException, IOException { + rows.data.postfix(state, trans, cache, xgen); + } + }); + + } + + protected String title(TRANS trans) { + return title; + } + + public static class Cells { + public static final Cells EMPTY = new Cells(); + private Cells() { + cells = new AbsCell[0][0]; + msg = "No Data Found"; + } + + public Cells(ArrayList arrayCells, String msg) { + cells = new AbsCell[arrayCells.size()][]; + arrayCells.toArray(cells); + this.msg = msg; + } + public AbsCell[][] cells; + public String msg; + + } + + public interface Data, TRANS extends Trans> { + // Note: Trans is not first to avoid Method Name Collision + public void prefix(S state, TRANS trans, final Cache cache, final HTMLGen hgen); + public Cells get(TRANS trans,S state); + public void postfix(S state, TRANS trans, final Cache cache, final HTMLGen hgen); + public String[] headers(); + } + + private class Rows extends DynamicCode { + private Data data; + private int alt; + + public Rows(Data data, int alt) { + this.data = data; + this.alt = alt; + } + + @Override + public void code(final S state, final TRANS trans, final Cache cache, final HTMLGen hgen) throws APIException, IOException { + Mark tr = new Mark(); + Mark td = new Mark(); + + int alt = this.alt; + Cells cells = data.get(trans,state); + if(cells.cells.length>0) { + for(AbsCell[] row : cells.cells) { + if(row.length==0) { + hgen.text("") + .hr() + .text(""); + } else { + switch(alt) { + case 1: + alt=2; + case 0: + hgen.incr(tr,TR); + break; + default: + alt=1; + hgen.incr(tr,TR,"class=alt"); + } + for(AbsCell cell :row) { + hgen.leaf(td, TD,cell.attrs()); + cell.write(hgen); + hgen.end(td); + } + hgen.end(tr); + } + } + // Pass Msg back to Table code, in order to place after Table Complete + if(cells.msg!=null) { + trans.put(ROW_MSG_SLOT,cells.msg); + } + } else { + trans.put(EMPTY_TABLE_SLOT,cells.msg); + } + } + } + +// public Table setPrefix(DynamicCode dynamicCode) { +// prefix = dynamicCode; +// return this; +// } +// +// public Table setPostfix(DynamicCode dynamicCode) { +// postfix = dynamicCode; +// return this; +// } + +} diff --git a/auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/XFrameFilter.java b/auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/XFrameFilter.java new file mode 100644 index 00000000..ae71d5bf --- /dev/null +++ b/auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/XFrameFilter.java @@ -0,0 +1,73 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ +package org.onap.aaf.auth.gui; + +import java.io.IOException; + +import javax.servlet.Filter; +import javax.servlet.FilterChain; +import javax.servlet.FilterConfig; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.http.HttpServletResponse; + +public class XFrameFilter implements Filter { + enum TYPE {none,self}; + // Note: Content-Security Params need to be worked out for GUI before activating. + private final String xframe;//,csp; + + public XFrameFilter(TYPE type) { + switch(type) { + case self: + xframe="SAMEORIGIN"; +// csp="default-src 'self'"; + break; + case none: + default: + xframe="DENY"; +// csp="default-src 'none'"; + break; + + } + } + + @Override + public void doFilter(ServletRequest req, ServletResponse resp, FilterChain fc) throws IOException, ServletException { + if(resp instanceof HttpServletResponse) { + @SuppressWarnings("unused") + HttpServletResponse hresp = (HttpServletResponse)resp; + ((HttpServletResponse)resp).addHeader("X-Frame-Options", xframe); +// ((HttpServletResponse)resp).addHeader("Content-Security-Policy",csp); + } + fc.doFilter(req, resp); + } + + @Override + public void init(FilterConfig fc) throws ServletException { + } + + @Override + public void destroy() { + } + + +} diff --git a/auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/pages/ApiDocs.java b/auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/pages/ApiDocs.java new file mode 100644 index 00000000..05ee21b0 --- /dev/null +++ b/auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/pages/ApiDocs.java @@ -0,0 +1,334 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.gui.pages; + +import java.io.IOException; +import java.net.ConnectException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; + +import org.onap.aaf.auth.env.AuthzTrans; +import org.onap.aaf.auth.gui.AAF_GUI; +import org.onap.aaf.auth.gui.BreadCrumbs; +import org.onap.aaf.auth.gui.NamedCode; +import org.onap.aaf.auth.gui.Page; +import org.onap.aaf.auth.gui.Table; +import org.onap.aaf.auth.gui.Table.Cells; +import org.onap.aaf.auth.gui.table.AbsCell; +import org.onap.aaf.auth.gui.table.TableData; +import org.onap.aaf.auth.gui.table.TextCell; +import org.onap.aaf.auth.rserv.HttpMethods; +import org.onap.aaf.cadi.CadiException; +import org.onap.aaf.cadi.Symm; +import org.onap.aaf.cadi.client.Future; +import org.onap.aaf.cadi.client.Rcli; +import org.onap.aaf.cadi.client.Retryable; +import org.onap.aaf.misc.env.APIException; +import org.onap.aaf.misc.env.Env; +import org.onap.aaf.misc.env.TimeTaken; +import org.onap.aaf.misc.xgen.Cache; +import org.onap.aaf.misc.xgen.html.HTMLGen; + +import aaf.v2_0.Api; +import aaf.v2_0.Api.Route; + +public class ApiDocs extends Page { + // Package on purpose + private static final String HREF = "/gui/api"; + private static final String NAME = "AAF RESTful API"; + private static final String fields[] = {}; + private static final String ERROR_LINK = "JSON " + + "XML "; + + + public ApiDocs(final AAF_GUI gui, final Page ... breadcrumbs) throws APIException, IOException { + super(gui.env,NAME,HREF, fields, + new BreadCrumbs(breadcrumbs), + new Preamble(gui), + new Table("AAF API Reference",gui.env.newTransNoAvg(),new Model(), "class=std") + ); + } + + private static class Preamble extends NamedCode { + + private static final String I = "i"; + private final String fs_url; + + public Preamble(AAF_GUI gui) { + super(false, "preamble"); + fs_url = gui.access.getProperty("fs_url", ""); + } + + @Override + public void code(Cache cache, HTMLGen xgen) throws APIException, IOException { + xgen.leaf(HTMLGen.H1).text("AAF 2.0 RESTful interface").end() + .hr(); + xgen.leaf(HTMLGen.H2).text("Accessing RESTful").end(); + xgen.incr(HTMLGen.UL) + .leaf(HTMLGen.LI).text("AAF RESTful service is secured by the following:").end() + .incr(HTMLGen.UL) + .leaf(HTMLGen.LI).text("The Client must utilize HTTP/S. Non Secure HTTP is not acceptable").end() + .leaf(HTMLGen.LI).text("The Client MUST supply an Identity validated by one of the following mechanisms").end() + .incr(HTMLGen.UL) + .leaf(HTMLGen.LI).text("Valid Global Login Cookie (CSP)").end() + .leaf(HTMLGen.LI).text("BASIC AUTH protocol using CSO Registered MechID, provisioned in AAF").end() + .leaf(HTMLGen.LI).text("BASIC AUTH protocol using ATTUID@csp.att.com, Global Login Password").end() + .leaf(HTMLGen.LI).text("(Available 3rd Qtr 2015) Valid tGuard Login Cookie").end() + .leaf(HTMLGen.LI).text("(Near Future) Application level Certificate").end() + .end() + .end() + .leaf(HTMLGen.LI).text("Responses").end() + .incr(HTMLGen.UL) + .leaf(HTMLGen.LI).text("Each API Entity listed shows what structure will be accepted by service (ContentType) " + + "or responded with by service (Accept). Therefore, use these in making your call. Critical for PUT/POST.").end() + .leaf(HTMLGen.LI).text("Each API call may respond with JSON or XML. Choose the ContentType/Accept that has " + + "+json after the type for JSON or +xml after the Type for XML").end() + .leaf(HTMLGen.LI).text("XSDs for Versions").end() + .incr(HTMLGen.UL) + .leaf(HTMLGen.LI).leaf(HTMLGen.A,"href=" + fs_url + "/aaf_2_0.xsd").text("API 2.0").end().end() + .end() + .leaf(HTMLGen.LI).text("AAF can support multiple Versions of the API. Choose the ContentType/Accept that has " + + "the appropriate version=?.?").end() + .leaf(HTMLGen.LI).text("All Errors coming from AAF return AT&T Standard Error Message as a String: " + ERROR_LINK + + " (does not apply to errors from Container)").end() + .end() + .leaf(HTMLGen.LI).text("Character Restrictions").end() + .incr(HTMLGen.UL) + .leaf(HTMLGen.LI).text("Character Restrictions must depend on the Enforcement Point used").end() + .leaf(HTMLGen.LI).text("Most AAF usage will be AAF Enforcement Point Characters for Instance and Action are:") + .br().br().leaf(I).text("a-zA-Z0-9,.()_-=%").end() + .br().br().text("For Instance, you may declare a multi-dimensional key with : (colon) separator, example:").end() + .br().leaf(I).text(":myCluster:myKeyspace").end() + .br().br().text("The * (asterix) may be used as a wild-card by itself or within the multi-dimensional key, example:") + .br().leaf(I).text(":myCluster:*").end() + .br().br().text("The % (percent) character can be used as an Escape Character. Applications can use % followed by 2 hexadecimal " + + "digits to cover odd keys. It is their code, however, which must translate.") + .br().br().text("The = (equals) is allowed so that Applications can pass Base64 encodations of binary keys").end() + .leaf(HTMLGen.LI).text("Ask for a Consultation on how these are typically used, or, if your tool is the only Enforcement Point, if set may be expanded").end() + .end() + .end(); + /* + + The Content is defined in the AAF XSD - TODO Add aaf.xsd”; + Character Restrictions + + URLs impose restrictions on characters which have specific meanings. This means you cannot have these characters in the Field Content you send + “#” is a “Fragment URL”, or anchor. Content after this Character is not sent. AAF cannot do anything about this… don’t use it. + “?=&”. These are used to delineate Parameters. + “/“ is used to separate fields + */ + } + + }; + /** + * Implement the Table Content for Permissions by User + * + * @author Jonathan + * + */ + private static class Model extends TableData { + public static final String[] HEADERS = new String[] {"Entity","Method","Path Info","Description"}; + private static final TextCell BLANK = new TextCell(""); + + @Override + public String[] headers() { + return HEADERS; + } + + + @Override + public Cells get(final AuthzTrans trans, final AAF_GUI gui) { + final ArrayList ns = new ArrayList(); + final ArrayList perms = new ArrayList(); + final ArrayList roles = new ArrayList(); + final ArrayList user = new ArrayList(); + final ArrayList aafOnly = new ArrayList(); + final ArrayList rv = new ArrayList(); + + + final TimeTaken tt = trans.start("AAF APIs",Env.REMOTE); + try { + gui.clientAsUser(trans.getUserPrincipal(), new Retryable() { + @SuppressWarnings("unchecked") + @Override + public Void code(Rcli client) throws CadiException, ConnectException, APIException { + Future fa = client.read("/api",gui.getDF(Api.class)); + if(fa.get(5000)) { + tt.done(); + TimeTaken tt2 = trans.start("Load Data", Env.SUB); + try { + if(fa.value!=null)for(Route r : fa.value.getRoute()) { + String path = r.getPath(); + // Build info + StringBuilder desc = new StringBuilder(); + + desc.append("

    "); + desc.append(r.getDesc()); + + if(r.getComments().size()>0) { + for(String ct : r.getComments()) { + desc.append("

    "); + desc.append(ct); + } + } + + if(r.getParam().size()>0) { + desc.append("


    Parameters

    "); + + for(String params : r.getParam()) { + String param[] = params.split("\\s*\\|\\s*"); + desc.append("

    "); + desc.append(param[0]); + desc.append(" : "); + desc.append(param[1]); + if("true".equalsIgnoreCase(param[2])) { + desc.append(" (Required)"); + } + } + } + + + if(r.getExpected()!=0) { + desc.append("

    Expected HTTP Code

    "); + desc.append(r.getExpected()); + } + + if(r.getExplicitErr().size()!=0) { + desc.append("

    Explicit HTTP Error Codes

    "); + boolean first = true; + for(int ee : r.getExplicitErr()) { + if(first) { + first = false; + } else { + desc.append(", "); + } + desc.append(ee); + } + } + + desc.append("

    "); + desc.append("GET".equals(r.getMeth())?"Accept:":"ContentType:"); + Collections.sort(r.getContentType()); + if(r.getPath().startsWith("/authn/basicAuth")) { + desc.append("

    text/plain"); + } + for(String ct : r.getContentType()) { + if(ct.contains("version=2")) { + desc.append("

    "); + desc.append(ct); + desc.append(""); + } + } + desc.append("

    "); + + + AbsCell[] sa = new AbsCell[] { + null, + new TextCell(r.getMeth(),"class=right"), + new TextCell(r.getPath()), + new TextCell(desc.toString()), + }; + + if(path.startsWith("/authz/perm")) { + sa[0] = perms.size()==0?new TextCell("PERMISSION"):BLANK; + perms.add(sa); + } else if(path.startsWith("/authz/role") || path.startsWith("/authz/userRole")) { + sa[0] = roles.size()==0?new TextCell("ROLE"):BLANK; + roles.add(sa); + } else if(path.startsWith("/authz/ns")) { + sa[0] = ns.size()==0?new TextCell("NAMESPACE"):BLANK; + ns.add(sa); + } else if(path.startsWith("/authn/basicAuth") + || path.startsWith("/authn/validate") + || path.startsWith("/authz/user")) { + sa[0] = user.size()==0?new TextCell("USER"):BLANK; + user.add(sa); + } else { + sa[0] = aafOnly.size()==0?new TextCell("AAF ONLY"):BLANK; + aafOnly.add(sa); + } + } + //TODO if(trans.fish(p)) + prepare(rv, perms,roles,ns,user); + } finally { + tt2.done(); + } + } else { + gui.writeError(trans, fa, null, 0); + } + return null; + } + }); + } catch (Exception e) { + trans.error().log(e.getMessage()); + } finally { + tt.done(); + } + + return new Cells(rv,null); + } + + @SuppressWarnings("unchecked") + private void prepare(ArrayList rv, ArrayList ... all) { + AbsCell lead; + AbsCell[] row; + for(ArrayList al : all) { + if(al.size()>1) { + row = al.get(0); + lead = row[0]; + row[0]=BLANK; + al.get(0).clone()[0]=BLANK; + Collections.sort(al, new Comparator() { + @Override + public int compare(AbsCell[] ca1, AbsCell[] ca2) { + int meth = ((TextCell)ca1[2]).name.compareTo( + ((TextCell)ca2[2]).name); + if(meth == 0) { + return (HttpMethods.valueOf(((TextCell)ca1[1]).name).compareTo( + HttpMethods.valueOf(((TextCell)ca2[1]).name))); + } else { + return meth; + } + } + }); + // set new first row + al.get(0)[0]=lead; + + rv.addAll(al); + } + } + } + } +} diff --git a/auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/pages/ApiExample.java b/auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/pages/ApiExample.java new file mode 100644 index 00000000..a98a16ca --- /dev/null +++ b/auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/pages/ApiExample.java @@ -0,0 +1,133 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.gui.pages; + +import java.io.IOException; + +import org.onap.aaf.auth.env.AuthzTrans; +import org.onap.aaf.auth.gui.AAF_GUI; +import org.onap.aaf.auth.gui.BreadCrumbs; +import org.onap.aaf.auth.gui.NamedCode; +import org.onap.aaf.auth.gui.Page; +import org.onap.aaf.cadi.Symm; +import org.onap.aaf.cadi.client.Future; +import org.onap.aaf.misc.env.APIException; +import org.onap.aaf.misc.env.Env; +import org.onap.aaf.misc.env.TimeTaken; +import org.onap.aaf.misc.xgen.Cache; +import org.onap.aaf.misc.xgen.DynamicCode; +import org.onap.aaf.misc.xgen.Mark; +import org.onap.aaf.misc.xgen.html.HTMLGen; + +/** + * Detail Page for Permissions + * + * @author Jonathan + * + */ +public class ApiExample extends Page { + public static final String HREF = "/gui/example/:tc"; + public static final String NAME = "APIExample"; + + public ApiExample(final AAF_GUI gui, Page ... breadcrumbs) throws APIException, IOException { + super(gui.env, NAME, HREF, 2/*backdots*/, new String[] {"API Code Example"}, + new BreadCrumbs(breadcrumbs), + new Model(NAME) + ); + } + + private static class Model extends NamedCode { + private static final String WITH_OPTIONAL_PARAMETERS = "\n\n////////////\n Data with Optional Parameters \n////////////\n\n"; + + public Model(String name) { + super(false,name); + } + + @Override + public void code(Cache cache, HTMLGen xgen) throws APIException, IOException { + Mark inner = xgen.divID("inner"); + xgen.divID("example","class=std"); + cache.dynamic(xgen, new DynamicCode() { + @Override + public void code(final AAF_GUI gui, final AuthzTrans trans, Cache cache, HTMLGen xgen) throws APIException, IOException { + TimeTaken tt = trans.start("Code Example",Env.REMOTE); + try { + final String typecode; + int prefix = trans.path().lastIndexOf('/')+1; + String encoded = trans.path().substring(prefix); + typecode = Symm.base64noSplit.decode(encoded); + Future fp = gui.client().read("/api/example/" + encoded, + "application/Void+json" + ); + Future fs2; + if(typecode.contains("Request+")) { + fs2 = gui.client().read("/api/example/" + encoded+"?optional=true", + "application/Void+json" + ); + } else { + fs2=null; + } + + + if(fp.get(5000)) { + xgen.incr(HTMLGen.H1).text("Sample Code").end() + .incr(HTMLGen.H5).text(typecode).end(); + xgen.incr("pre"); + if(typecode.contains("+xml")) { + xgen.xml(fp.body()); + if(fs2!=null && fs2.get(5000)) { + xgen.text(WITH_OPTIONAL_PARAMETERS); + xgen.xml(fs2.body()); + } + } else { + xgen.text(fp.body()); + if(fs2!=null && fs2.get(5000)) { + xgen.text(WITH_OPTIONAL_PARAMETERS); + xgen.text(fs2.body()); + } + } + xgen.end(); + } else { + xgen.incr(HTMLGen.H3) + .textCR(2,"Error from AAF Service") + .end(); + gui.writeError(trans, fp, xgen, 0); + } + + } catch (APIException e) { + throw e; + } catch (IOException e) { + throw e; + } catch (Exception e) { + throw new APIException(e); + }finally { + tt.done(); + } + } + + }); + xgen.end(inner); + } + } + +} + \ No newline at end of file diff --git a/auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/pages/ApprovalAction.java b/auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/pages/ApprovalAction.java new file mode 100644 index 00000000..2797cd66 --- /dev/null +++ b/auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/pages/ApprovalAction.java @@ -0,0 +1,121 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.gui.pages; + +import java.io.IOException; + +import org.onap.aaf.auth.env.AuthzTrans; +import org.onap.aaf.auth.gui.AAF_GUI; +import org.onap.aaf.auth.gui.BreadCrumbs; +import org.onap.aaf.auth.gui.NamedCode; +import org.onap.aaf.auth.gui.Page; +import org.onap.aaf.cadi.CadiException; +import org.onap.aaf.cadi.client.Future; +import org.onap.aaf.cadi.client.Rcli; +import org.onap.aaf.cadi.client.Retryable; +import org.onap.aaf.misc.env.APIException; +import org.onap.aaf.misc.env.Env; +import org.onap.aaf.misc.env.Slot; +import org.onap.aaf.misc.env.TimeTaken; +import org.onap.aaf.misc.xgen.Cache; +import org.onap.aaf.misc.xgen.DynamicCode; +import org.onap.aaf.misc.xgen.html.HTMLGen; + +import aaf.v2_0.Approval; +import aaf.v2_0.Approvals; + +public class ApprovalAction extends Page { + public ApprovalAction(final AAF_GUI gui, final Page ... breadcrumbs) throws APIException, IOException { + super(gui.env,"Approvals",ApprovalForm.HREF, ApprovalForm.FIELDS, + new BreadCrumbs(breadcrumbs), + new NamedCode(true,"content") { + final Slot sAppr = gui.env.slot(ApprovalForm.NAME+'.'+ApprovalForm.FIELDS[0]); + final Slot sUser = gui.env.slot(ApprovalForm.NAME+'.'+ApprovalForm.FIELDS[1]); + + @Override + public void code(final Cache cache, final HTMLGen hgen) throws APIException, IOException { + cache.dynamic(hgen, new DynamicCode() { + @Override + public void code(final AAF_GUI gui, final AuthzTrans trans,final Cache cache, final HTMLGen hgen) throws APIException, IOException { + String[] appr = trans.get(sAppr,null); + String user = trans.get(sUser,null); + String lastPage = ApprovalForm.HREF; + if (user != null) { + lastPage += "?user="+user; + } + + if(appr==null) { + hgen.p("No Approvals have been selected."); + } else { + Approval app; + final Approvals apps = new Approvals(); + int count = 0; + for(String a : appr) { + if(a!=null) { + int idx = a.indexOf('|'); + if(idx>=0) { + app = new Approval(); + app.setStatus(a.substring(0,idx)); + app.setTicket(a.substring(++idx)); + app.setApprover(trans.getUserPrincipal().getName()); + apps.getApprovals().add(app); + ++count; + } + } + } + if(apps.getApprovals().isEmpty()) { + hgen.p("No Approvals have been sent."); + } else { + TimeTaken tt = trans.start("AAF Update Approvals",Env.REMOTE); + try { + final int total = count; + gui.clientAsUser(trans.getUserPrincipal(), new Retryable() { + @Override + public Boolean code(Rcli client) throws APIException, CadiException { + boolean fail2 = true; + Future fa = client.update("/authz/approval",gui.getDF(Approvals.class),apps); + if(fa.get(AAF_GUI.TIMEOUT)) { + // Do Remote Call + fail2 = false; + hgen.p(total + (total==1?" Approval has":" Approvals have") + " been Saved"); + } else { + gui.writeError(trans, fa, hgen, 0); + } + return fail2; + } + }); + } catch (Exception e) { + e.printStackTrace(); + } finally { + tt.done(); + } + } + + hgen.br(); + hgen.incr("a",true,"class=greenbutton","href="+lastPage).text("Back").end(); + } + } + }); + } + }); + } +} diff --git a/auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/pages/ApprovalForm.java b/auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/pages/ApprovalForm.java new file mode 100644 index 00000000..da552aeb --- /dev/null +++ b/auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/pages/ApprovalForm.java @@ -0,0 +1,299 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.gui.pages; + +import java.io.IOException; +import java.net.ConnectException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; + +import org.onap.aaf.auth.env.AuthzEnv; +import org.onap.aaf.auth.env.AuthzTrans; +import org.onap.aaf.auth.gui.AAF_GUI; +import org.onap.aaf.auth.gui.BreadCrumbs; +import org.onap.aaf.auth.gui.Form; +import org.onap.aaf.auth.gui.NamedCode; +import org.onap.aaf.auth.gui.Page; +import org.onap.aaf.auth.gui.Table; +import org.onap.aaf.auth.gui.Table.Cells; +import org.onap.aaf.auth.gui.table.AbsCell; +import org.onap.aaf.auth.gui.table.ButtonCell; +import org.onap.aaf.auth.gui.table.RadioCell; +import org.onap.aaf.auth.gui.table.RefCell; +import org.onap.aaf.auth.gui.table.TableData; +import org.onap.aaf.auth.gui.table.TextAndRefCell; +import org.onap.aaf.auth.gui.table.TextCell; +import org.onap.aaf.auth.org.Organization; +import org.onap.aaf.auth.org.OrganizationFactory; +import org.onap.aaf.auth.org.Organization.Identity; +import org.onap.aaf.cadi.CadiException; +import org.onap.aaf.cadi.client.Future; +import org.onap.aaf.cadi.client.Rcli; +import org.onap.aaf.cadi.client.Retryable; +import org.onap.aaf.misc.env.APIException; +import org.onap.aaf.misc.env.Env; +import org.onap.aaf.misc.env.Slot; +import org.onap.aaf.misc.env.TimeTaken; +import org.onap.aaf.misc.xgen.Cache; +import org.onap.aaf.misc.xgen.DynamicCode; +import org.onap.aaf.misc.xgen.Mark; +import org.onap.aaf.misc.xgen.html.HTMLGen; + +import aaf.v2_0.Approval; +import aaf.v2_0.Approvals; + +public class ApprovalForm extends Page { + // Package on purpose + static final String NAME="Approvals"; + static final String HREF = "/gui/approve"; + static final String[] FIELDS = new String[] {"line[]","user"}; + + + public ApprovalForm(final AAF_GUI gui, final Page ... breadcrumbs) throws APIException, IOException { + super(gui.env,NAME,HREF, FIELDS, + + new BreadCrumbs(breadcrumbs), + new NamedCode(false, "filterByUser") { + @Override + public void code(final Cache cache, final HTMLGen hgen) throws APIException, IOException { + cache.dynamic(hgen, new DynamicCode() { + @Override + public void code(final AAF_GUI gui, final AuthzTrans trans, final Cache cache, final HTMLGen hgen) throws APIException, IOException { + String user = trans.get(trans.env().slot(NAME+".user"),""); + hgen.incr("p", "class=userFilter") + .text("Filter by User:") + .tagOnly("input", "type=text", "value="+user, "id=userTextBox") + .tagOnly("input", "type=button", "onclick=userFilter('"+HREF+"');", "value=Go!") + .end(); + } + }); + } + }, + new Form(true,new Table("Approval Requests", gui.env.newTransNoAvg(),new Model(gui.env),"class=stdform")) + .preamble("The following requires your Approval to proceed in the AAF System.

    Hover on Identity for Name; click for WebPhone; If Deny is the only option, User is no longer valid."), + new NamedCode(false, "selectAlljs") { + @Override + public void code(final Cache cache, final HTMLGen hgen) throws APIException, IOException { + Mark jsStart = new Mark(); + hgen.js(jsStart); + hgen.text("function selectAll(radioClass) {"); + hgen.text("var radios = document.querySelectorAll(\".\"+radioClass);"); + hgen.text("for (i = 0; i < radios.length; i++) {"); + hgen.text("radios[i].checked = true;"); + hgen.text("}"); + hgen.text("}"); + hgen.end(jsStart); + } + }); + + } + + /** + * Implement the Table Content for Approvals + * + * @author Jonathan + * + */ + private static class Model extends TableData { + //TODO come up with a generic way to do ILM Info (people page) + private static final String TODO_ILM_INFO = "TODO: ILM Info"; + private static final String DOMAIN_OF_USER = "@DOMAIN"; + + private static final String[] headers = new String[] {"Identity","Request","Approve","Deny"}; + private Slot sUser; + + public Model(AuthzEnv env) { + sUser = env.slot(NAME+".user"); + } + + @Override + public String[] headers() { + return headers; + } + + @Override + public Cells get(final AuthzTrans trans, final AAF_GUI gui) { + final String userParam = trans.get(sUser, null); + ArrayList rv = new ArrayList(); + String msg = null; + TimeTaken tt = trans.start("AAF Get Approvals for Approver",Env.REMOTE); + try { + final List pendingApprovals = new ArrayList(); + final List beginIndicesPerApprover = new ArrayList(); + int numLeft = gui.clientAsUser(trans.getUserPrincipal(), new Retryable() { + @Override + public Integer code(Rcli client) throws CadiException, ConnectException, APIException { + Future fa = client.read("/authz/approval/approver/"+trans.user(),gui.getDF(Approvals.class)); + int numLeft = 0; + if(fa.get(AAF_GUI.TIMEOUT)) { + + if(fa.value!=null) { + for (Approval appr : fa.value.getApprovals()) { + if (appr.getStatus().equals("pending")) { + if (userParam!=null) { + if (!appr.getUser().equalsIgnoreCase(userParam)) { + numLeft++; + continue; + } + } + pendingApprovals.add(appr); + } + } + } + + String prevApprover = null; + int overallIndex = 0; + + for (Approval appr : pendingApprovals) { + String currApprover = appr.getApprover(); + if (!currApprover.equals(prevApprover)) { + prevApprover = currApprover; + beginIndicesPerApprover.add(overallIndex); + } + overallIndex++; + } + } + return numLeft; + } + }); + + if (pendingApprovals.size() > 0) { + // Only add select all links if we have approvals + AbsCell[] selectAllRow = new AbsCell[] { + AbsCell.Null, + AbsCell.Null, + new ButtonCell("all", "onclick=selectAll('approve')", "class=selectAllButton"), + new ButtonCell("all", "onclick=selectAll('deny')", "class=selectAllButton") + }; + rv.add(selectAllRow); + } + + int line=-1; + + while (beginIndicesPerApprover.size() > 0) { + int beginIndex = beginIndicesPerApprover.remove(0); + int endIndex = (beginIndicesPerApprover.isEmpty()?pendingApprovals.size():beginIndicesPerApprover.get(0)); + List currApproverList = pendingApprovals.subList(beginIndex, endIndex); + + String currApproverFull = currApproverList.get(0).getApprover(); + String currApproverShort = currApproverFull.substring(0,currApproverFull.indexOf('@')); + String currApprover = (trans.user().indexOf('@')<0?currApproverShort:currApproverFull); + if (!currApprover.equals(trans.user())) { + AbsCell[] approverHeader; + if (currApproverFull.substring(currApproverFull.indexOf('@')).equals(DOMAIN_OF_USER)) { + approverHeader = new AbsCell[] { + new TextAndRefCell("Approvals Delegated to Me by ", currApprover, + TODO_ILM_INFO + currApproverShort, + true, + new String[] {"colspan=4", "class=head"}) + }; + } else { + approverHeader = new AbsCell[] { + new TextCell("Approvals Delegated to Me by " + currApprover, + new String[] {"colspan=4", "class=head"}) + }; + } + rv.add(approverHeader); + } + + // Sort by User Requesting + Collections.sort(currApproverList, new Comparator() { + @Override + public int compare(Approval a1, Approval a2) { + return a1.getUser().compareTo(a2.getUser()); + } + }); + + String prevUser = null; + boolean userOK=true; + + for (Approval appr : currApproverList) { + if(++line0) { + msg = "After these, there will be " + numLeft + " approvals left to process"; + } + if(rv.size()==0) { + if (numLeft>0) { + msg = "No Approvals to process at this time for user " + userParam +". You have " + + numLeft + " other approvals to process."; + } else { + msg = "No Approvals to process at this time"; + } + } + } catch (Exception e) { + trans.error().log(e); + } finally { + tt.done(); + } + return new Cells(rv,msg); + } + } +} diff --git a/auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/pages/CMArtiChangeAction.java b/auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/pages/CMArtiChangeAction.java new file mode 100644 index 00000000..1bf0ed76 --- /dev/null +++ b/auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/pages/CMArtiChangeAction.java @@ -0,0 +1,219 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.gui.pages; + +import java.io.IOException; +import java.net.ConnectException; + +import org.onap.aaf.auth.cmd.AAFcli; +import org.onap.aaf.auth.env.AuthzTrans; +import org.onap.aaf.auth.gui.AAF_GUI; +import org.onap.aaf.auth.gui.BreadCrumbs; +import org.onap.aaf.auth.gui.NamedCode; +import org.onap.aaf.auth.gui.Page; +import org.onap.aaf.cadi.CadiException; +import org.onap.aaf.cadi.client.Future; +import org.onap.aaf.cadi.client.Holder; +import org.onap.aaf.cadi.client.Rcli; +import org.onap.aaf.cadi.client.Retryable; +import org.onap.aaf.cadi.util.Vars; +import org.onap.aaf.misc.env.APIException; +import org.onap.aaf.misc.env.Slot; +import org.onap.aaf.misc.env.Data.TYPE; +import org.onap.aaf.misc.env.util.IPValidator; +import org.onap.aaf.misc.env.util.Split; +import org.onap.aaf.misc.xgen.Cache; +import org.onap.aaf.misc.xgen.DynamicCode; +import org.onap.aaf.misc.xgen.html.HTMLGen; + +import aaf.v2_0.Error; +import certman.v1_0.Artifacts; +import certman.v1_0.Artifacts.Artifact; + +public class CMArtiChangeAction extends Page { + public CMArtiChangeAction(final AAF_GUI gui, final Page ... breadcrumbs) throws APIException, IOException { + super(gui.env,CMArtiChangeForm.NAME,CMArtiChangeForm.HREF, CMArtiChangeForm.fields, + new BreadCrumbs(breadcrumbs), + new NamedCode(true,"content") { + final Slot sID = gui.env.slot(CMArtiChangeForm.NAME+'.'+CMArtiChangeForm.fields[0]); + final Slot sMachine = gui.env.slot(CMArtiChangeForm.NAME+'.'+CMArtiChangeForm.fields[1]); + final Slot sNS = gui.env.slot(CMArtiChangeForm.NAME+'.'+CMArtiChangeForm.fields[2]); + final Slot sDirectory = gui.env.slot(CMArtiChangeForm.NAME+'.'+CMArtiChangeForm.fields[3]); + final Slot sCA = gui.env.slot(CMArtiChangeForm.NAME+'.'+CMArtiChangeForm.fields[4]); + final Slot sOSUser = gui.env.slot(CMArtiChangeForm.NAME+'.'+CMArtiChangeForm.fields[5]); + final Slot sRenewal = gui.env.slot(CMArtiChangeForm.NAME+'.'+CMArtiChangeForm.fields[6]); + final Slot sNotify = gui.env.slot(CMArtiChangeForm.NAME+'.'+CMArtiChangeForm.fields[7]); + final Slot sCmd = gui.env.slot(CMArtiChangeForm.NAME+'.'+CMArtiChangeForm.fields[8]); + final Slot sOther = gui.env.slot(CMArtiChangeForm.NAME+'.'+CMArtiChangeForm.fields[9]); + final Slot sType = gui.env.slot(CMArtiChangeForm.NAME+'.'+CMArtiChangeForm.fields[10]); + final Slot sSans = gui.env.slot(CMArtiChangeForm.NAME+'.'+CMArtiChangeForm.fields[11]); + + @Override + public void code(final Cache cache, final HTMLGen hgen) throws APIException, IOException { + cache.dynamic(hgen, new DynamicCode() { + @Override + public void code(final AAF_GUI gui, final AuthzTrans trans,final Cache cache, final HTMLGen hgen) throws APIException, IOException { +trans.info().log("Step 1"); + final Artifact arti = new Artifact(); + final String machine = trans.get(sMachine,null); + final String ca = trans.get(sCA, null); + final String sans = ((String)trans.get(sSans,null)); + if(sans!=null) { + for(String s: Split.splitTrim(',', sans)) { + arti.getSans().add(s); + } + } + // Disallow IP entries, except by special Permission + if(!trans.fish(getPerm(ca,"ip"))) { + boolean ok=true; + if(IPValidator.ip(machine)) { + ok=false; + } + if(ok) { + for(String s: arti.getSans()) { + if(IPValidator.ip(s)) { + ok=false; + break; + } + } + } + if(!ok) { + hgen.p("Policy Failure: IPs in certificates are only allowed by Exception."); + return; + } + } + + // Disallow Domain based Definitions without exception + if(machine.startsWith("*")) { // Domain set + if(!trans.fish(getPerm(ca, "domain"))) { + hgen.p("Policy Failure: Domain Artifact Declarations are only allowed by Exception."); + return; + } + } + + arti.setMechid((String)trans.get(sID,null)); + arti.setMachine(machine); + arti.setNs((String)trans.get(sNS,null)); + arti.setDir((String)trans.get(sDirectory,null)); + arti.setCa(ca); + arti.setOsUser((String)trans.get(sOSUser, null)); + arti.setRenewDays(Integer.parseInt((String)trans.get(sRenewal, null))); + arti.setNotification((String)trans.get(sNotify, null)); + String[] checkbox = trans.get(sType,null); + for(int i=0;i ok = new Holder(false); + final Holder deleted = new Holder(false); + Future f = gui.cmClientAsUser(trans.getUserPrincipal(), new Retryable>() { + @Override + public Future code(Rcli client)throws CadiException, ConnectException, APIException { + Future rv = null; + switch((String)trans.get(sCmd, "")) { + case CMArtiChangeForm.CREATE: + Future fc; + rv = fc = client.create("/cert/artifacts", gui.artifactsDF, artifacts); + if(fc.get(AAFcli.timeout())) { + hgen.p("Created Artifact " + arti.getMechid() + " on " + arti.getMachine()); + ok.set(true); + } + break; + case CMArtiChangeForm.UPDATE: + Future fu = client.update("/cert/artifacts", gui.artifactsDF, artifacts); + if((rv=fu).get(AAFcli.timeout())) { + hgen.p("Artifact " + arti.getMechid() + " on " + arti.getMachine() + " is updated"); + ok.set(true); + } + break; + case CMArtiChangeForm.COPY: + Future future = client.read("/cert/artifacts/"+arti.getMechid()+'/'+arti.getMachine(), gui.artifactsDF); + rv = future; + if(future.get(AAFcli.timeout())) { + for(Artifact a : future.value.getArtifact()) { // only one, because these two are key + for(String newMachine :Split.split(',', trans.get(sOther, ""))) { + a.setMachine(newMachine); + Future fup = client.update("/cert/artifacts", gui.artifactsDF, future.value); + if(fup.get(AAFcli.timeout())) { + hgen.p("Copied to " + newMachine); + ok.set(true); + } + } + } + } + break; + case CMArtiChangeForm.DELETE: + Future fv; + rv = fv = client.delete("/cert/artifacts/"+arti.getMechid()+"/"+arti.getMachine(),"application/json"); + if(fv.get(AAFcli.timeout())) { + hgen.p("Deleted " + arti.getMechid() + " on " + arti.getMachine()); + ok.set(true); + deleted.set(true); + } + break; + } + return rv; + } + }); + if(!ok.get()) { + if(f==null) { + hgen.p("Unknown Command"); + } else { + if(f.body().contains("%")) { + Error err = gui.getDF(Error.class).newData().in(TYPE.JSON).load(f.body()).asObject(); + hgen.p(Vars.convert(err.getText(),err.getVariables())); + } else { + hgen.p(arti.getMechid() + " on " + arti.getMachine() + ": " + f.body()); + } + } + } + hgen.br().leaf(HTMLGen.A,"class=greenbutton","href="+(deleted.get()?CMArtifactShow.HREF:CMArtiChangeForm.HREF)+ + "?id="+arti.getMechid()+ + "&machine="+arti.getMachine() + + "&ns="+arti.getNs()) + .text("Back") + .end(); + + } catch (Exception e) { + hgen.p("Unknown Error"); + e.printStackTrace(); + } + + } + hgen.br(); + } + }); + } + }); + } +} diff --git a/auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/pages/CMArtiChangeForm.java b/auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/pages/CMArtiChangeForm.java new file mode 100644 index 00000000..c65e7db5 --- /dev/null +++ b/auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/pages/CMArtiChangeForm.java @@ -0,0 +1,256 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.gui.pages; + +import static org.onap.aaf.misc.xgen.html.HTMLGen.TABLE; + +import java.io.IOException; +import java.net.ConnectException; + +import org.onap.aaf.auth.cmd.AAFcli; +import org.onap.aaf.auth.env.AuthzTrans; +import org.onap.aaf.auth.gui.AAF_GUI; +import org.onap.aaf.auth.gui.BreadCrumbs; +import org.onap.aaf.auth.gui.NamedCode; +import org.onap.aaf.auth.gui.Page; +import org.onap.aaf.auth.org.Organization; +import org.onap.aaf.auth.org.OrganizationException; +import org.onap.aaf.auth.org.OrganizationFactory; +import org.onap.aaf.auth.org.Organization.Identity; +import org.onap.aaf.cadi.CadiException; +import org.onap.aaf.cadi.LocatorException; +import org.onap.aaf.cadi.client.Future; +import org.onap.aaf.cadi.client.Rcli; +import org.onap.aaf.cadi.client.Retryable; +import org.onap.aaf.cadi.util.FQI; +import org.onap.aaf.misc.env.APIException; +import org.onap.aaf.misc.env.Slot; +import org.onap.aaf.misc.xgen.Cache; +import org.onap.aaf.misc.xgen.DynamicCode; +import org.onap.aaf.misc.xgen.Mark; +import org.onap.aaf.misc.xgen.html.HTMLGen; + +import certman.v1_0.Artifacts; +import certman.v1_0.Artifacts.Artifact; + +public class CMArtiChangeForm extends Page { + private static final String COPY_ARTIFACT = "copyArtifact"; + private static final String DELETE_ARTIFACT = "deleteArtifact"; + + // Package on purpose + static final String HREF = "/gui/artichange"; + static final String NAME = "ArtifactChange"; + static final String fields[] = {"id","machine","ns","directory","ca","osuser","renewal","notify","cmd","others","types[]","sans"}; + + static final String types[] = {"jks","file","script"}; + static final String UPDATE = "Update"; + static final String CREATE = "Create"; + static final String COPY = "Copy"; + static final String DELETE = "Delete"; + + public CMArtiChangeForm(final AAF_GUI gui, final Page ... breadcrumbs) throws APIException, IOException { + super(gui.env,NAME,HREF, fields, + new BreadCrumbs(breadcrumbs), + new NamedCode(true,"content") { + private final Slot sID = gui.env.slot(CMArtiChangeForm.NAME+'.'+CMArtiChangeForm.fields[0]); + private final Slot sMach = gui.env.slot(CMArtiChangeForm.NAME+'.'+CMArtiChangeForm.fields[1]); + private final Slot sNS = gui.env.slot(CMArtiChangeForm.NAME+'.'+CMArtiChangeForm.fields[2]); + + @Override + public void code(final Cache cache, final HTMLGen hgen) throws APIException, IOException { + Mark js = new Mark(); + Mark fn = new Mark(); + hgen.js(js).function(fn,COPY_ARTIFACT) + .text("f=document.getElementById('"+fields[9]+"')") + .text("s=document.getElementById('theButton')") + .text("cmd=document.getElementById('"+fields[8]+"')") + .text("ins=document.getElementById('instruct')") + .text("c=document.getElementById('cbcopy')") + .text("trd=document.getElementById('trdelete')") + .li("if (c.checked==true) {" , + "f.style.display=ins.style.display='block'", + "trd.style.display='none'", + "s.orig=s.value;", + "s.value='Copy'", + "cmd.setAttribute('value',s.value)", + "} else {", + "f.style.display=ins.style.display='none';", + "trd.style.display='block'", + "s.value=s.orig", + "cmd.setAttribute('value',s.orig)", + "}" + ) + .end(fn) + .function(fn, DELETE_ARTIFACT) + .text("d=document.getElementById('cbdelete')") + .text("trc=document.getElementById('trcopy')") + .text("s=document.getElementById('theButton')") + .text("cmd=document.getElementById('"+fields[8]+"')") + .li("if (d.checked==true) {", + "s.orig=s.value;", + "s.value='Delete';", + "trc.style.display='none';", + "cmd.setAttribute('value',s.value);", + "} else {", + "s.value=s.orig;", + "trc.style.display='block';", + "cmd.setAttribute('value',s.orig);", + "}" + ) + .end(js); + + hgen.leaf(HTMLGen.TITLE).text("Certificate Artifact Form").end(); + Mark form = new Mark(); + hgen.incr(form, "form","action="+HREF,"method=post"); + + cache.dynamic(hgen, new DynamicCode() { + @Override + public void code(final AAF_GUI gui, final AuthzTrans trans, final Cache cache, final HTMLGen hgen) throws APIException, IOException { + + final String incomingMach = trans.get(sMach,""); + String incomingNS = trans.get(sNS,""); + String id= trans.get(sID, ""); + final String incomingID = id.indexOf('@')>=0?id:id+'@'+FQI.reverseDomain(incomingNS); + + String submitText=UPDATE; + boolean delete=true; + try { + Artifact arti =gui.cmClientAsUser(trans.getUserPrincipal(), new Retryable() { + @Override + public Artifact code(Rcli client) throws CadiException, ConnectException, APIException { + Future fa = client.read("/cert/artifacts/"+incomingID+'/'+incomingMach, gui.artifactsDF); + if(fa.get(AAFcli.timeout())) { + for(Artifact arti : fa.value.getArtifact()) { + return arti; // just need the first one + } + } + return null; + } + }); + if(arti==null) { + Organization org = OrganizationFactory.get(trans); + Identity user = org.getIdentity(trans, incomingID); + if(user==null) { + hgen.p("The mechID you typed, \"" + incomingID + "\", is not a valid " + org.getName() + " ID"); + return; + } + arti = new Artifact(); + arti.setMechid(incomingID); + Identity managedBy = user.responsibleTo(); + if(managedBy == null) { + arti.setSponsor("Unknown Sponsor"); + } else { + arti.setSponsor(managedBy.fullID()); + } + arti.setMachine(incomingMach); + arti.setNs(incomingNS); + arti.setDir(""); + arti.setCa("aaf"); + arti.setOsUser(""); + arti.setRenewDays(30); + arti.setNotification("mailto:"+user.email()); + arti.getType().add(types[0]); + arti.getType().add(types[2]); + submitText = CREATE; + delete = false; + } else { + if(arti.getNotification()==null) { + Organization org = OrganizationFactory.get(trans); + Identity user = org.getIdentity(trans, incomingID); + arti.setNotification("mailto:"+user.email()); + } + } + // CSO Approval no longer required for SAN use +// final String mechID = arti.getMechid(); +// boolean maySans=gui.lur.fish(new Principal() { +// @Override +// public String getName() { +// return mechID; +// }},getPerm(arti.getCa(),"san")); +// if(!maySans) { +// arti.getSans().clear(); +// } + Mark table = new Mark(TABLE); + hgen.incr(table) + .input(fields[0],"MechID*",true,"value="+arti.getMechid()) + .input("sponsor", "Sponsor",false,"value="+arti.getSponsor(),"readonly","style=border:none;background-color:white;") + .input(fields[1],"Machine*",true,"value="+arti.getMachine(),"style=width:130%;"); +// if(maySans) { + hgen.incr(HTMLGen.TR).incr(HTMLGen.TD).end() + .incr(HTMLGen.TD,"class=subtext").text("Use full machine names, "); + if(!trans.fish(getPerm(arti.getCa(),"ip"))) { + hgen.text("NO "); + } + StringBuilder sb = null; + for(String s: arti.getSans()) { + if(sb==null) { + sb = new StringBuilder(); + } else { + sb.append(", "); + } + sb.append(s); + } + + hgen.text("IPs allowed, separated by commas.").end() + .input(fields[11], "SANs", false, "value="+(sb==null?"":sb.toString()),"style=width:180%;"); +// } + hgen.input(fields[2],"Namespace",true,"value="+arti.getNs(),"style=width:180%;") + .input(fields[3],"Directory", true, "value="+arti.getDir(),"style=width:180%;") + .input(fields[4],"Certificate Authority",true,"value="+arti.getCa(),"style=width:180%;") + .input(fields[5],"O/S User",true,"value="+arti.getOsUser()) + .input(fields[6],"Renewal Days before Expiration", true, "value="+arti.getRenewDays(),"style=width:20%;") + .input(fields[7],"Notification",true,"value="+arti.getNotification()) + .incr(HTMLGen.TR) + .incr(HTMLGen.TD).leaf("label","for=types","required").text("Artifact Types").end(2) + .incr(HTMLGen.TD); + for(int i=0;i slotCode; + private enum Params{id,ns}; + + + public CMArtifactShow(final AAF_GUI gui, Page ... breadcrumbs) throws APIException, IOException { + super(gui.env, NAME, HREF, Params.values() , + new BreadCrumbs(breadcrumbs), + arti = new ArtiTable(gui.env) + ); + // Setting so we can get access to HTMLGen clone and Slots + arti.set(this,slotCode); + } + + private static class ArtiTable extends Table { + private static Model model; + private SlotCode sc; + enum Params {id,ns}; + public ArtiTable(AuthzEnv env) { + super((String)null,env.newTransNoAvg(),model = new Model(), + slotCode = new SlotCode(false,env,NAME,Params.values()) { + @Override + public void code(final Cache cache, final HTMLGen hgen) throws APIException, IOException { + cache.dynamic(hgen, new DynamicCode() { + @Override + public void code(AAF_GUI state, AuthzTrans trans, final Cache cache, final HTMLGen hgen) throws APIException, IOException { + Mark js = new Mark(); + hgen.js(js).function("newArtifact") + .text("machine=document.getElementById('machine');") + .text("window.open('" + +CMArtiChangeForm.HREF+ + "?id="+get(trans, Params.id,"")+ + "&ns="+get(trans, Params.ns,"")+ + "&machine='+machine.value,'_self');" + ).end(js); + hgen.leaf("input","id=machine","style=margin:1em 1em 1em 1em;width:30%").end(); + hgen.leaf(HTMLGen.A,"class=greenbutton","href=javascript:newArtifact()","style=color:white;").text("New Machine").end(); + } + }); + } + },"class=std"); + } + + + public void set(CMArtifactShow cmArtifactShow, SlotCode sc) { + this.sc = sc; + model.set(cmArtifactShow,sc); + } + + @Override + protected String title(AuthzTrans trans) { + StringBuilder sb = new StringBuilder("X509 Certificates"); + if(sc!=null) { // initialized + sb.append(" for "); + String id = sc.get(trans,Params.id,""); + sb.append(id); + if(id.indexOf('@')<0) { + sb.append('@'); + sb.append(FQI.reverseDomain(sc.get(trans, Params.ns,"missingDomain"))); + } + } + return sb.toString(); + } + } + /** + * Implement the table content for Cred Detail + * + * @author Jeremiah + * + */ + private static class Model implements Table.Data { + private CMArtifactShow cas; + private SlotCode sc; + + // Covering for Constructor Order + private void set(CMArtifactShow cas, SlotCode sc) { + this.cas = cas; + this.sc = sc; + } + + private static final String[] headers = new String[]{"Machine","Directory","CA","Renews","Expires",""}; + @Override + public String[] headers() { + return headers; + } + + @Override + public Cells get(final AuthzTrans trans, final AAF_GUI gui) { + String str = sc.get(trans,Params.id, null); + if(str==null) { + return Cells.EMPTY; + } + final String id = str.indexOf('@')>=0?str:str + '@' + FQI.reverseDomain(sc.get(trans,Params.ns, "")); + final ArrayList rv = new ArrayList(); + final TimeTaken tt = trans.start("AAF X509 Details",Env.REMOTE); + try { + gui.cmClientAsUser(trans.getUserPrincipal(),new Retryable() { + @Override + public Void code(Rcli client) throws CadiException, ConnectException, APIException { + Future fuCI = client.read("/cert/id/"+id,gui.certInfoDF); + Future fuArt = client.read("/cert/artifacts?mechid="+id, gui.artifactsDF); + + X509Certificate[] lc; + if(fuCI.get(AAFcli.timeout())) { + TimeTaken tt1 = trans.start("x509Certificate", Env.SUB); + try { + Collection xcs = Factory.toX509Certificate(fuCI.value.getCerts()); + lc = new X509Certificate[xcs.size()]; + xcs.toArray(lc); + } catch (CertificateException e) { + trans.error().log(e,"Bad Certificate entry"); + throw new CadiException(e); + } finally { + tt1.done(); + } + } else { + lc = null; + trans.error().log("Cannot retrieve Certificates for " + id); + } + if(fuArt.get(AAFcli.timeout())) { + for(Artifact arti : fuArt.value.getArtifact()) { + StringWriter sw = new StringWriter(); + HTMLGen hgen = cas.clone(sw); + Mark mark = new Mark(); + hgen.leaf(HTMLGen.A,"class=button", + "href="+CMArtiChangeForm.HREF+"?id="+arti.getMechid() +"&machine="+arti.getMachine()+"&ns="+arti.getNs()) + .text("Details") + .end(mark); + Date last = null; + if(lc!=null) { + for(X509Certificate xc : lc) { + if(xc.getSubjectDN().getName().contains("CN="+arti.getMachine())) { + if(last==null || last.before(xc.getNotAfter())) { + last = xc.getNotAfter(); + } + } + } + } + GregorianCalendar renew; + if(last!=null) { + renew = new GregorianCalendar(); + renew.setTime(last); + renew.add(GregorianCalendar.DAY_OF_MONTH,arti.getRenewDays()*-1); + } else { + renew = null; + } + + rv.add(new AbsCell[] { + new TextCell(arti.getMachine(),"style=width:20%;"), + new TextCell(arti.getDir(),"style=width:25%;"), + new TextCell(arti.getCa(),"style=width:2%;text-align:center;"), + new TextCell(renew==null? + arti.getRenewDays().toString() + " days before Exp": + Chrono.dateOnlyStamp(renew),"style=width:6%;text-align:center;"), + new TextCell(last==null?"None Deployed":Chrono.dateOnlyStamp(last),"style=width:5%;text-align:center;"), + new TextCell(sw.toString(),"style=width:10%;text-align:center;") + }); + } + } else { + rv.add(new AbsCell[] {new TextCell("*** Data Unavailable ***")}); + } + return null; + } + }); + } catch (Exception e) { + e.printStackTrace(); + } finally { + tt.done(); + } + return new Cells(rv,null); + } + + @Override + public void prefix(AAF_GUI state, AuthzTrans trans, final Cache cache, final HTMLGen hgen) { + } + + @Override + public void postfix(AAF_GUI state, AuthzTrans trans, final Cache cache, final HTMLGen hgen) { + } + + } + +} diff --git a/auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/pages/CredDetail.java b/auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/pages/CredDetail.java new file mode 100644 index 00000000..8c7c8763 --- /dev/null +++ b/auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/pages/CredDetail.java @@ -0,0 +1,352 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.gui.pages; + +import java.io.IOException; +import java.io.StringWriter; +import java.net.ConnectException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; + +import javax.xml.datatype.XMLGregorianCalendar; + +import org.onap.aaf.auth.cmd.AAFcli; +import org.onap.aaf.auth.env.AuthzTrans; +import org.onap.aaf.auth.gui.AAF_GUI; +import org.onap.aaf.auth.gui.BreadCrumbs; +import org.onap.aaf.auth.gui.Page; +import org.onap.aaf.auth.gui.SlotCode; +import org.onap.aaf.auth.gui.Table; +import org.onap.aaf.auth.gui.Table.Cells; +import org.onap.aaf.auth.gui.table.AbsCell; +import org.onap.aaf.auth.gui.table.TableData; +import org.onap.aaf.auth.gui.table.TextCell; +import org.onap.aaf.cadi.CadiException; +import org.onap.aaf.cadi.client.Future; +import org.onap.aaf.cadi.client.Rcli; +import org.onap.aaf.cadi.client.Retryable; +import org.onap.aaf.cadi.util.FQI; +import org.onap.aaf.misc.env.APIException; +import org.onap.aaf.misc.env.Env; +import org.onap.aaf.misc.env.TimeTaken; +import org.onap.aaf.misc.env.util.Chrono; +import org.onap.aaf.misc.xgen.Cache; +import org.onap.aaf.misc.xgen.DynamicCode; +import org.onap.aaf.misc.xgen.Mark; +import org.onap.aaf.misc.xgen.html.HTMLGen; + +import aaf.v2_0.Users; +import aaf.v2_0.Users.User; +import certman.v1_0.Artifacts; +import certman.v1_0.Artifacts.Artifact; + +public class CredDetail extends Page { + + public static final String HREF = "/gui/creddetail"; + public static final String NAME = "CredDetail"; + private static Model model; + private static SlotCode slotCode; + enum Params {id,ns}; + + + public CredDetail(final AAF_GUI gui, Page ... breadcrumbs) throws APIException, IOException { + super(gui.env, NAME, HREF, Params.values(), + new BreadCrumbs(breadcrumbs), + new Table("Cred Details",gui.env.newTransNoAvg(),model = new Model(), + slotCode = new SlotCode(false,gui.env,NAME,Params.values()) { + @Override + public void code(final Cache cache, final HTMLGen hgen) throws APIException, IOException { + cache.dynamic(hgen, new DynamicCode() { + @Override + public void code(AAF_GUI state, AuthzTrans trans, final Cache cache, final HTMLGen hgen) throws APIException, IOException { + String ns = get(trans, Params.ns,""); + String domain = FQI.reverseDomain(ns); + Mark js = new Mark(), fn=new Mark(); + hgen.js(js).function(fn,"newArtifact") + .text("id=document.getElementById('id');") + .text("if(id.value=='') {alert('Enter the id in box');} else {") + .text("window.open('"+CMArtiChangeForm.HREF+"?id='+id.value+'&ns="+ns+"','_self');}" + ) + .end(fn) + .function("newPassword") + .text("id=document.getElementById('id');") + .text("if(id.value=='') {alert('Enter the id in box');} else {") + .text("window.open('"+PassChangeForm.HREF+"?id='+id.value+'@"+domain+"&ns="+ns+"','_self');}" + ) + .end(js); + hgen.leaf("i","style=margin:1em 0em 1em 1em;").text("ID:").end() + .leaf("input","id=id","style=width:10%;").end().text("@").text(domain).br() + .leaf(HTMLGen.A,"class=greenbutton","href=javascript:newArtifact()","style=color:white;margin:1.2em 0em 1em 1em;").text("As Cert Artifact").end() + .leaf(HTMLGen.A,"class=greenbutton","href=javascript:newPassword()","style=color:white;margin:1.2em 0em 1em 1em;").text("w/Password").end() + ; + } + }); + } + },"class=std") + + ); + // Setting so we can get access to HTMLGen clone + model.set(this,slotCode); + } + + + + /** + * Implement the table content for Cred Detail + * + * @author Jeremiah + * + */ + private static class Model extends TableData { + private static final String STYLE_WIDTH_5 = "style=width:5%;"; + private static final String STYLE_WIDTH_10 = "style=width:10%;"; + private static final String STYLE_WIDTH_15 = "style=width:15%;"; + private static final String STYLE_WIDTH_20 = "style=width:20%;"; + private static final String STYLE_WIDTH_70 = "style=width:70%;"; + private SlotCode sc; + private CredDetail cd; + // Covering for Constructor Order + private void set(CredDetail credDetail, SlotCode slotCode) { + cd = credDetail; + sc = slotCode; + } + + @Override + public void prefix(AAF_GUI state, AuthzTrans trans, final Cache cache, final HTMLGen hgen) { + } + + @Override + public Cells get(final AuthzTrans trans, final AAF_GUI gui) { + final String ns = sc.get(trans, Params.ns, ""); + final String id = sc.get(trans, Params.id, ""); + if(ns==null) { + return Cells.EMPTY; + } + final ArrayList rv = new ArrayList(); + final TimeTaken tt = trans.start("AAF Cred Details",Env.REMOTE); + List la; + try { + la = gui.cmClientAsUser(trans.getUserPrincipal(), new Retryable>() { + @Override + public List code(Rcli client)throws CadiException, ConnectException, APIException { + Future fa = client.read("/cert/artifacts?ns="+ns,gui.artifactsDF); + if(fa.get(AAFcli.timeout())) { + return fa.value.getArtifact(); + } else { + return null; + } + } + + }); + final Set lns = new HashSet(); + if(la!=null) { + for(Artifact a : la){ + lns.add(a.getMechid()); + } + } + gui.clientAsUser(trans.getUserPrincipal(),new Retryable() { + @Override + public Void code(Rcli client) throws CadiException, ConnectException, APIException { + Future fu = client.read("/authn/creds/ns/"+ns,gui.getDF(Users.class)); + if(fu.get(AAFcli.timeout())) { + // Organize User entries + Map>>> users = new HashMap>>>(); + + List>> lmu=null; + Map> mu = null; + List lu = null; + + for (User u : fu.value.getUser()) { + if(u.getType() == 200) { + lns.remove(u.getId()); + } + lmu = users.get(u.getId()); + if(lmu==null) { + users.put(u.getId(),lmu=new ArrayList>>()); + } + mu=null; + for(Map> xmu : lmu) { + if(xmu.containsKey(u.getType())) { + mu = xmu; + } + } + + if(mu==null) { + lmu.add(mu=new HashMap>()); + } + + lu = mu.get(u.getType()); + if(lu==null) { + mu.put(u.getType(),lu = new ArrayList()); + } + lu.add(u); + } + + int count=0; + for (Entry>>> ulm : users.entrySet()) { + String key = "cred_"+count++; + StringWriter buttons = new StringWriter(); + HTMLGen hgen = cd.clone(buttons); + hgen.leaf("button","onclick=divVisibility('"+key+"');","class=button").text("Expand").end(); + + StringWriter creds = new StringWriter(); + hgen = cd.clone(creds); + Mark div = hgen.divID(key,ulm.getKey().equals(id)?"":"style=display:none;"); + for(Map> miu : ulm.getValue()) { + Mark utable = new Mark(); + hgen.leaf(utable,HTMLGen.TABLE); + + Mark uRow = new Mark(); + String cls; + boolean first = true; + + for( Entry> es : miu.entrySet()) { + Collections.sort(es.getValue(),new Comparator() { + @Override + public int compare(User u1, User u2) { + int rv = u1.getType().compareTo(u2.getType()); + return rv==0?u2.getExpires().compare(u1.getExpires()):rv; + } + }); + int xcnt = 0; + XMLGregorianCalendar oldest=null, newest=null; + String id = null; + for(User u: es.getValue()) { + if(id==null) { + id = u.getId(); + } + // Need to compile entries for Certificates on this screen + if(es.getKey()==200) { + ++xcnt; + if(oldest==null || oldest.compare(u.getExpires())<0) { + oldest = u.getExpires(); + } + if(newest==null || newest.compare(u.getExpires())<0) { + newest = u.getExpires(); + } + } else { + hgen.leaf(uRow,HTMLGen.TR); + if(first) { + hgen.leaf(HTMLGen.TD,cls="class=detailFirst",STYLE_WIDTH_10); + switch(es.getKey()) { + case 1: + case 2: hgen.text("Password"); + break; + case 10: hgen.text("Certificate"); break; + } + } else { + hgen.leaf(HTMLGen.TD,cls="class=detail",STYLE_WIDTH_10+"text-align:center;").text("\""); + } + hgen.end(); + hgen.incr(HTMLGen.TD,cls,STYLE_WIDTH_20); + + hgen.leaf(HTMLGen.A, + "class=button", + "href="+PassDeleteAction.HREF+ + "?id="+id+ + "&ns="+ns+ + "&date="+u.getExpires().toXMLFormat() + + "&type="+u.getType()) + .text("Delete").end(); + if(first && es.getKey()<10) { // Change Password Screen + hgen.leaf(HTMLGen.A,"class=button","href="+PassChangeForm.HREF+"?id="+id+"&ns="+ns) + .text("Add") + .end(); + } + first=false; + hgen.end().leaf(HTMLGen.TD,cls,STYLE_WIDTH_70) + .text(Chrono.niceDateStamp(u.getExpires())) + .end(); + + hgen.end(uRow); + } + } + if(xcnt>0) { // print compilations, if any, of Certificate + hgen.leaf(uRow,HTMLGen.TR) + .leaf(HTMLGen.TD,cls="class=detailFirst",STYLE_WIDTH_10).text("x509").end() + .leaf(HTMLGen.TD, cls,STYLE_WIDTH_20) + .leaf(HTMLGen.A,"class=button","href="+CMArtifactShow.HREF+"?id="+id+"&ns="+ns) + .text("View All") + .end(2) + .leaf(HTMLGen.TD, cls,STYLE_WIDTH_70).text(String.format( + xcnt>0?"%d Certificate%s, ranging from %s to %s" + :"%d Certificate%s", + xcnt, + xcnt==1?"":"s", + Chrono.niceDateStamp(oldest), + Chrono.niceDateStamp(newest))) + .end(uRow); + + } + } + hgen.end(utable); + } + + hgen.end(div); + + rv.add(new AbsCell[] { + new TextCell(ulm.getKey(),STYLE_WIDTH_15), + new TextCell(buttons.toString(),STYLE_WIDTH_5), + new TextCell(creds.toString(),STYLE_WIDTH_70) + }); + } + for(String missing : lns) { + StringWriter buttons = new StringWriter(); + HTMLGen hgen = cd.clone(buttons); + hgen.leaf(HTMLGen.A,"class=button","href="+CMArtifactShow.HREF+"?id="+missing+"&ns="+ns) + .text("View All") + .end(2); + rv.add(new AbsCell[] { + new TextCell(missing,STYLE_WIDTH_15), + new TextCell(buttons.toString(),STYLE_WIDTH_5), + new TextCell("No X509 Credential Instantiated") + }); + } + + } else { + rv.add(new AbsCell[] {new TextCell("*** Data Unavailable ***")}); + } + return null; + } + }); + } catch (Exception e) { + e.printStackTrace(); + } finally { + tt.done(); + } + return new Cells(rv,null); + } + + @Override + public void postfix(AAF_GUI state, AuthzTrans trans, final Cache cache, final HTMLGen hgen) { + } + + + } +} diff --git a/auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/pages/Home.java b/auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/pages/Home.java new file mode 100644 index 00000000..caad42b5 --- /dev/null +++ b/auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/pages/Home.java @@ -0,0 +1,77 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.gui.pages; + +import static org.onap.aaf.misc.xgen.html.HTMLGen.A; +import static org.onap.aaf.misc.xgen.html.HTMLGen.H3; + +import java.io.IOException; + +import org.onap.aaf.auth.gui.AAF_GUI; +import org.onap.aaf.auth.gui.NamedCode; +import org.onap.aaf.auth.gui.Page; +import org.onap.aaf.misc.env.APIException; +import org.onap.aaf.misc.xgen.Cache; +import org.onap.aaf.misc.xgen.Mark; +import org.onap.aaf.misc.xgen.html.HTMLGen; + + +public class Home extends Page { + public static final String HREF = "/gui/home"; + public Home(final AAF_GUI gui) throws APIException, IOException { + super(gui.env,"Home",HREF, NO_FIELDS, new NamedCode(false,"content") { + @Override + public void code(final Cache cache, final HTMLGen xgen) throws APIException, IOException { +// // TEMP +// JSGen jsg = xgen.js(); +// jsg.function("httpPost","sURL","sParam") +// .text("var oURL = new java.net.URL(sURL)") +// .text("var oConn = oURL.openConnection();") +// .text("oConn.setDoInput(true);") +// .text("oConn.setDoOutpu(true);") +// .text("oConn.setUseCaches(false);") +// .text("oConn.setRequestProperty(\"Content-Type\",\"application/x-www-form-urlencoded\");") +// .text(text) +// jsg.done(); + // TEMP + final Mark pages = xgen.divID("Pages"); + xgen.leaf(H3).text("Choose from the following:").end() + .leaf(A,"href=myperms").text("My Permissions").end() + .leaf(A,"href=myroles").text("My Roles").end() + // TODO: uncomment when on cassandra 2.1.2 for MyNamespace GUI page + .leaf(A,"href=ns").text("My Namespaces").end() + .leaf(A,"href=approve").text("My Approvals").end() + .leaf(A, "href=myrequests").text("My Pending Requests").end() + // Enable later +// .leaf(A, "href=onboard").text("Onboarding").end() + // Password Change. If logged in as CSP/GSO, go to their page + .leaf(A,"href=passwd").text("Password Management").end() + .leaf(A,"href=cui").text("Command Prompt").end() + .leaf(A,"href=api").text("AAF API").end() + ; + + xgen.end(pages); + } + }); + } + +} diff --git a/auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/pages/LoginLanding.java b/auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/pages/LoginLanding.java new file mode 100644 index 00000000..7dcc65aa --- /dev/null +++ b/auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/pages/LoginLanding.java @@ -0,0 +1,115 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.gui.pages; + +import java.io.IOException; +import java.net.URLDecoder; + +import javax.servlet.http.HttpServletRequest; + +import org.onap.aaf.auth.env.AuthzTrans; +import org.onap.aaf.auth.gui.AAF_GUI; +import org.onap.aaf.auth.gui.NamedCode; +import org.onap.aaf.auth.gui.Page; +import org.onap.aaf.cadi.config.Config; +import org.onap.aaf.misc.env.APIException; +import org.onap.aaf.misc.xgen.Cache; +import org.onap.aaf.misc.xgen.DynamicCode; +import org.onap.aaf.misc.xgen.Mark; +import org.onap.aaf.misc.xgen.html.HTMLGen; + +public class LoginLanding extends Page { + public static final String HREF = "/login"; + static final String NAME = "Login"; + static final String fields[] = {"id","password","environment"}; + static final String envs[] = {"DEV","TEST","PROD"}; + + public LoginLanding(final AAF_GUI gui, final Page ... breadcrumbs) throws APIException, IOException { + super(gui.env, NAME,HREF, fields, new NamedCode(true, "content") { + @Override + public void code(final Cache cache, final HTMLGen hgen) throws APIException, IOException { + hgen.leaf("p").text("No login credentials are found in your current session. " + + "Choose your preferred login option to continue.").end(); + + Mark loginPaths = hgen.divID("Pages"); + + cache.dynamic(hgen, new DynamicCode() { + @Override + public void code(AAF_GUI authGUI, AuthzTrans trans, Cache cache, HTMLGen xgen) throws APIException, IOException { + HttpServletRequest req = trans.get(gui.slot_httpServletRequest, null); + if(req!=null) { + String query = req.getQueryString(); + if(query!=null) { + for(String qs : query.split("&")) { + int equals = qs.indexOf('='); + xgen.leaf(HTMLGen.A, "href="+URLDecoder.decode(qs.substring(equals+1),Config.UTF_8)).text(qs.substring(0,equals).replace('_', ' ')).end(); + } + } + } + xgen.leaf(HTMLGen.A, "href=gui/home?Authentication=BasicAuth").text("AAF Basic Auth").end(); + } + }); +// hgen.leaf("a", "href=#","onclick=divVisibility('cso');").text("Global Login").end() +// .incr("p", "id=cso","style=display:none").text("this will redirect to global login").end() +// .leaf("a", "href=#","onclick=divVisibility('tguard');").text("tGuard").end() +// .incr("p", "id=tguard","style=display:none").text("this will redirect to tGuard login").end() +// hgen.leaf("a", "href=#","onclick=divVisibility('basicauth');").text("AAF Basic Auth").end(); + hgen.end(loginPaths); + +// hgen.incr("form","method=post","style=display:none","id=basicauth","gui/home?Authentication=BasicAuth"); +// Mark table = new Mark(TABLE); +// hgen.incr(table); +// cache.dynamic(hgen, new DynamicCode() { +// @Override +// public void code(final AuthGUI gui, final AuthzTrans trans, final Cache cache, final HTMLGen hgen) +// throws APIException, IOException { +// hgen +// .input(fields[0],"Username",true) +// .input(fields[1],"Password",true, "type=password"); +// Mark selectRow = new Mark(); +// hgen +// .incr(selectRow, "tr") +// .incr("td") +// .incr("label", "for=envs", "required").text("Environment").end() +// .end() +// .incr("td") +// .incr("select", "name=envs", "id=envs", "required") +// .incr("option", "value=").text("Select Environment").end(); +// for (String env : envs) { +// hgen.incr("option", "value="+env).text(env).end(); +// } +// hgen +// .end(selectRow) + +// hgen.end(); +// } +// }); +// hgen.end(); +// hgen.tagOnly("input", "type=submit", "value=Submit") +// .tagOnly("input", "type=reset", "value=Reset") +// .end(); + + + } + }); + } +} diff --git a/auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/pages/LoginLandingAction.java b/auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/pages/LoginLandingAction.java new file mode 100644 index 00000000..9ab3fa71 --- /dev/null +++ b/auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/pages/LoginLandingAction.java @@ -0,0 +1,65 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.gui.pages; + +import java.io.IOException; + +import org.onap.aaf.auth.env.AuthzTrans; +import org.onap.aaf.auth.gui.AAF_GUI; +import org.onap.aaf.auth.gui.BreadCrumbs; +import org.onap.aaf.auth.gui.NamedCode; +import org.onap.aaf.auth.gui.Page; +import org.onap.aaf.misc.env.APIException; +import org.onap.aaf.misc.env.Slot; +import org.onap.aaf.misc.xgen.Cache; +import org.onap.aaf.misc.xgen.DynamicCode; +import org.onap.aaf.misc.xgen.html.HTMLGen; + +public class LoginLandingAction extends Page { + public LoginLandingAction(final AAF_GUI gui, final Page ... breadcrumbs) throws APIException, IOException { + super(gui.env,"Login",LoginLanding.HREF, LoginLanding.fields, + new BreadCrumbs(breadcrumbs), + new NamedCode(true,"content") { + final Slot sID = gui.env.slot(LoginLanding.NAME+'.'+LoginLanding.fields[0]); +// final Slot sPassword = gui.env.slot(LoginLanding.NAME+'.'+LoginLanding.fields[1]); + + @Override + public void code(final Cache cache, final HTMLGen hgen) throws APIException, IOException { + cache.dynamic(hgen, new DynamicCode() { + @Override + public void code(final AAF_GUI gui, final AuthzTrans trans,final Cache cache, final HTMLGen hgen) throws APIException, IOException { + String username = trans.get(sID,null); +// String password = trans.get(sPassword,null); + + hgen.p("User: "+username); + hgen.p("Pass: ********"); + + // TODO: clarification from JG + // put in request header? + // then pass through authn/basicAuth call? + + } + }); + } + }); + } +} diff --git a/auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/pages/NsDetail.java b/auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/pages/NsDetail.java new file mode 100644 index 00000000..5df050bf --- /dev/null +++ b/auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/pages/NsDetail.java @@ -0,0 +1,247 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.gui.pages; + +import java.io.IOException; +import java.io.StringWriter; +import java.net.ConnectException; +import java.util.ArrayList; +import java.util.List; + +import org.onap.aaf.auth.cmd.AAFcli; +import org.onap.aaf.auth.env.AuthzTrans; +import org.onap.aaf.auth.gui.AAF_GUI; +import org.onap.aaf.auth.gui.BreadCrumbs; +import org.onap.aaf.auth.gui.Page; +import org.onap.aaf.auth.gui.Table; +import org.onap.aaf.auth.gui.Table.Cells; +import org.onap.aaf.auth.gui.table.AbsCell; +import org.onap.aaf.auth.gui.table.RefCell; +import org.onap.aaf.auth.gui.table.TableData; +import org.onap.aaf.auth.gui.table.TextCell; +import org.onap.aaf.auth.validation.Validator; +import org.onap.aaf.cadi.CadiException; +import org.onap.aaf.cadi.client.Future; +import org.onap.aaf.cadi.client.Rcli; +import org.onap.aaf.cadi.client.Retryable; +import org.onap.aaf.cadi.config.Config; +import org.onap.aaf.misc.env.APIException; +import org.onap.aaf.misc.env.Env; +import org.onap.aaf.misc.env.Slot; +import org.onap.aaf.misc.env.TimeTaken; +import org.onap.aaf.misc.xgen.html.HTMLGen; + +import aaf.v2_0.Nss; +import aaf.v2_0.Nss.Ns; +import aaf.v2_0.Perm; +import aaf.v2_0.Perms; +import aaf.v2_0.Role; +import aaf.v2_0.Roles; + +public class NsDetail extends Page { + + public static final String HREF = "/gui/nsdetail"; + public static final String NAME = "NsDetail"; + static final String WEBPHONE = "http://webphone.att.com/cgi-bin/webphones.pl?id="; + public static enum NS_FIELD { OWNERS, ADMINS, ROLES, PERMISSIONS, CREDS}; + private static final String BLANK = ""; + private static Slot keySlot; + private static Model model; + private static String gw_url; + + + public NsDetail(final AAF_GUI gui, Page ... breadcrumbs) throws APIException, IOException { + super(gui.env, NAME, HREF, new String[] {"ns"}, + new BreadCrumbs(breadcrumbs), + new Table("Namespace Details",gui.env.newTransNoAvg(),model=new Model(),"class=detail") + ); + model.set(this); + keySlot = gui.env.slot(NAME+".ns"); + gw_url = gui.env.getProperty(Config.GW_URL); + if(gw_url==null) { + gw_url=""; + } else { + gw_url+="/aaf/2.0"; + } + } + + /** + * Implement the table content for Namespace Detail + * + * @author Jeremiah + * + */ + private static class Model extends TableData { + private static final String CSP_ATT_COM = "@csp.att.com"; + private NsDetail nd; + + public void set(NsDetail nsDetail) { + nd=nsDetail; + } + + @Override + public Cells get(final AuthzTrans trans, final AAF_GUI gui) { + final String nsName = trans.get(keySlot, null); + Validator v = new Validator(); + v.ns(nsName); + if(v.err()) { + trans.warn().printf("Error in NsDetail Request: %s", v.errs()); + return Cells.EMPTY; + } + + if(nsName==null) { + return Cells.EMPTY; + } + final ArrayList rv = new ArrayList(); + rv.add(new AbsCell[]{new TextCell("Name:"),new TextCell(nsName)}); + + final TimeTaken tt = trans.start("AAF Namespace Details",Env.REMOTE); + try { + gui.clientAsUser(trans.getUserPrincipal(),new Retryable() { + @Override + public Void code(Rcli client) throws CadiException, ConnectException, APIException { + Future fn = client.read("/authz/nss/"+nsName,gui.getDF(Nss.class)); + + if(fn.get(AAF_GUI.TIMEOUT)) { + tt.done(); + try { +// TimeTaken tt = trans.start("Load Data", Env.SUB); + + for(Ns n : fn.value.getNs()) { + String desc = (n.getDescription()!=null?n.getDescription():BLANK); + rv.add(new AbsCell[]{new TextCell("Description:"),new TextCell(desc)}); + + addField(trans, nsName, rv, n.getAdmin(), NS_FIELD.ADMINS); + addField(trans, nsName, rv, n.getResponsible(), NS_FIELD.OWNERS); + + StringWriter sw = new StringWriter(); + HTMLGen hgen = nd.clone(sw); + hgen.leaf(HTMLGen.A, "class=greenbutton","href="+CredDetail.HREF+"?ns="+nsName).text("Cred Details").end(); + rv.add(new AbsCell[] { + new TextCell("Credentials"), + new TextCell(sw.toString()) + }); + + + Future fr = client.read( + "/authz/roles/ns/"+nsName, + gui.getDF(Roles.class) + ); + List roles = new ArrayList(); + if(fr.get(AAFcli.timeout())) { + for (Role r : fr.value.getRole()) { + roles.add(r.getName()); + } + } + addField(trans, nsName, rv, roles, NS_FIELD.ROLES); + + + Future fp = client.read( + "/authz/perms/ns/"+nsName, + gui.getDF(Perms.class) + ); + List perms = new ArrayList(); + + if(fp.get(AAFcli.timeout())) { + for (Perm p : fp.value.getPerm()) { + perms.add(p.getType() + "|" + p.getInstance() + "|" + p.getAction()); + } + } + addField(trans, nsName, rv, perms, NS_FIELD.PERMISSIONS); + } + String historyLink = NsHistory.HREF + + "?name=" + nsName; + rv.add(new AbsCell[] {new RefCell("See History",historyLink,false)}); + } finally { + tt.done(); + } + } else { + rv.add(new AbsCell[] {new TextCell("*** Data Unavailable ***")}); + } + return null; + } + }); + } catch (Exception e) { + e.printStackTrace(); + } finally { + tt.done(); + } + return new Cells(rv,null); + } + + private void addField(AuthzTrans trans, String ns, List rv, List values, NS_FIELD field) { + if (!values.isEmpty()) { + switch(field) { + case OWNERS: + case ADMINS: + case CREDS: + for (int i=0; i< values.size(); i++) { + AbsCell label = (i==0?new TextCell(sentenceCase(field)+":"):AbsCell.Null); + String user = values.get(i); + AbsCell userCell = (user.endsWith(CSP_ATT_COM)? + new RefCell(user,WEBPHONE + user.substring(0,user.indexOf('@')),true):new TextCell(user)); + rv.add(new AbsCell[] { + label, + userCell + }); + } + break; + case ROLES: + for (int i=0; i< values.size(); i++) { + String role = values.get(i); + AbsCell label = (i==0?new TextCell(sentenceCase(field)+":"):AbsCell.Null); + rv.add(new AbsCell[] { + label, + new RefCell(role,RoleDetail.HREF+"?role="+role+"&ns="+ns,false) + }); + } + break; + case PERMISSIONS: + for (int i=0; i< values.size(); i++) { + AbsCell label = (i==0?new TextCell(sentenceCase(field)+":","style=width:20%"):AbsCell.Null); + String perm = values.get(i); + String[] fields = perm.split("\\|"); + String grantLink = gw_url + + PermGrantForm.HREF + + "?type=" + fields[0].trim() + + "&instance=" + fields[1].trim() + + "&action=" + fields[2].trim(); + + rv.add(new AbsCell[] { + label, + new TextCell(perm,"style=width:60%;"), + new RefCell("Grant", grantLink,false,"class=button","style=width:20%;") + }); + } + break; + } + + } + } + + private String sentenceCase(NS_FIELD field) { + String sField = field.toString(); + return sField.substring(0, 1).toUpperCase() + sField.substring(1).toLowerCase(); + } + + } +} diff --git a/auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/pages/NsHistory.java b/auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/pages/NsHistory.java new file mode 100644 index 00000000..414f992f --- /dev/null +++ b/auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/pages/NsHistory.java @@ -0,0 +1,230 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.gui.pages; + +import java.io.IOException; +import java.net.ConnectException; +import java.util.ArrayList; +import java.util.Calendar; +import java.util.Comparator; +import java.util.List; + +import org.onap.aaf.auth.env.AuthzEnv; +import org.onap.aaf.auth.env.AuthzTrans; +import org.onap.aaf.auth.gui.AAF_GUI; +import org.onap.aaf.auth.gui.BreadCrumbs; +import org.onap.aaf.auth.gui.NamedCode; +import org.onap.aaf.auth.gui.Page; +import org.onap.aaf.auth.gui.Table; +import org.onap.aaf.auth.gui.Table.Cells; +import org.onap.aaf.auth.gui.table.AbsCell; +import org.onap.aaf.auth.gui.table.RefCell; +import org.onap.aaf.auth.gui.table.TableData; +import org.onap.aaf.auth.gui.table.TextCell; +import org.onap.aaf.cadi.CadiException; +import org.onap.aaf.cadi.client.Future; +import org.onap.aaf.cadi.client.Rcli; +import org.onap.aaf.cadi.client.Retryable; +import org.onap.aaf.misc.env.APIException; +import org.onap.aaf.misc.env.Env; +import org.onap.aaf.misc.env.Slot; +import org.onap.aaf.misc.env.TimeTaken; +import org.onap.aaf.misc.xgen.Cache; +import org.onap.aaf.misc.xgen.DynamicCode; +import org.onap.aaf.misc.xgen.html.HTMLGen; + +import aaf.v2_0.History; +import aaf.v2_0.History.Item; + +public class NsHistory extends Page { + static final String NAME="NsHistory"; + static final String HREF = "/gui/nsHistory"; + static final String FIELDS[] = {"name","dates"}; + static final String WEBPHONE = "http://webphone.att.com/cgi-bin/webphones.pl?id="; + static enum Month { JANUARY, FEBRUARY, MARCH, APRIL, MAY, JUNE, JULY, + AUGUST, SEPTEMBER, OCTOBER, NOVEMBER, DECEMBER }; + + public NsHistory(final AAF_GUI gui, final Page ... breadcrumbs) throws APIException, IOException { + super(gui.env,NAME,HREF, FIELDS, + new BreadCrumbs(breadcrumbs), + new Table("History", gui.env.newTransNoAvg(),new Model(gui.env),"class=std"), + new NamedCode(true, "content") { + @Override + public void code(final Cache cache, final HTMLGen hgen) throws APIException, IOException { + final Slot name = gui.env.slot(NAME+".name"); + cache.dynamic(hgen, new DynamicCode() { + @Override + public void code(final AAF_GUI gui, final AuthzTrans trans, final Cache cache, final HTMLGen hgen) throws APIException, IOException { + String obName = trans.get(name, null); + + // Use Javascript to make the table title more descriptive + hgen.js() + .text("var caption = document.querySelector(\".title\");") + .text("caption.innerHTML='History for Namespace [ " + obName + " ]';") + .done(); + + // Use Javascript to change Link Target to our last visited Detail page + String lastPage = NsDetail.HREF + "?name=" + obName; + hgen.js() + .text("alterLink('nsdetail', '"+lastPage + "');") + .done(); + + hgen.br(); + hgen.leaf("a","href=#advanced_search","onclick=divVisibility('advanced_search');").text("Advanced Search").end() + .divID("advanced_search", "style=display:none"); + hgen.incr("table"); + + addDateRow(hgen,"Start Date"); + addDateRow(hgen,"End Date"); + hgen.incr("tr").incr("td"); + hgen.tagOnly("input", "type=button","value=Get History", + "onclick=datesURL('"+HREF+"?name=" + obName+"');"); + hgen.end().end(); + hgen.end(); + hgen.end(); + + } + }); + } + } + + ); + } + + private static void addDateRow(HTMLGen hgen, String s) { + hgen + .incr("tr") + .incr("td") + .incr("label", "for=month", "required").text(s+"*").end() + .end() + .incr("td") + .incr("select", "name=month"+s.substring(0, s.indexOf(' ')), "id=month"+s.substring(0, s.indexOf(' ')), "required") + .incr("option", "value=").text("Month").end(); + for (Month m : Month.values()) { + if (Calendar.getInstance().get(Calendar.MONTH) == m.ordinal()) { + hgen.incr("option", "selected", "value="+(m.ordinal()+1)).text(m.name()).end(); + } else { + hgen.incr("option", "value="+(m.ordinal()+1)).text(m.name()).end(); + } + } + hgen.end() + .end() + .incr("td") + .tagOnly("input","type=number","id=year"+s.substring(0, s.indexOf(' ')),"required", + "value="+Calendar.getInstance().get(Calendar.YEAR), "min=1900", + "max="+Calendar.getInstance().get(Calendar.YEAR), + "placeholder=Year").end() + .end(); + } + + + + + /** + * Implement the Table Content for History + * + * @author Jeremiah + * + */ + private static class Model extends TableData { + private static final String CSP_ATT_COM = "@csp.att.com"; + private static final String[] headers = new String[] {"Date","User","Memo"}; + private Slot name; + private Slot dates; + + public Model(AuthzEnv env) { + name = env.slot(NAME+".name"); + dates = env.slot(NAME+".dates"); + } + + @Override + public String[] headers() { + return headers; + } + + @Override + public Cells get(final AuthzTrans trans, final AAF_GUI gui) { + final String oName = trans.get(name,null); + final String oDates = trans.get(dates,null); + + if(oName==null) { + return Cells.EMPTY; + } + + final ArrayList rv = new ArrayList(); + String msg = null; + final TimeTaken tt = trans.start("AAF Get History for Namespace ["+oName+"]",Env.REMOTE); + try { + gui.clientAsUser(trans.getUserPrincipal(), new Retryable() { + @Override + public Void code(Rcli client) throws CadiException, ConnectException, APIException { + if (oDates != null) { + client.setQueryParams("yyyymm="+oDates); + } + Future fh = client.read("/authz/hist/ns/"+oName,gui.getDF(History.class)); + if (fh.get(AAF_GUI.TIMEOUT)) { + tt.done(); + TimeTaken tt2 = trans.start("Load History Data", Env.SUB); + try { + List histItems = fh.value.getItem(); + + java.util.Collections.sort(histItems, new Comparator() { + @Override + public int compare(Item o1, Item o2) { + return o2.getTimestamp().compare(o1.getTimestamp()); + } + }); + + for (Item i : histItems) { + String user = i.getUser(); + AbsCell userCell = (user.endsWith(CSP_ATT_COM)? + new RefCell(user,WEBPHONE + user.substring(0,user.indexOf('@')),true):new TextCell(user)); + + rv.add(new AbsCell[] { + new TextCell(i.getTimestamp().toGregorianCalendar().getTime().toString()), + userCell, + new TextCell(i.getMemo()) + }); + } + } finally { + tt2.done(); + } + } else { + if (fh.code()==403) { + rv.add(new AbsCell[] {new TextCell("You may not view History of Namespace [" + oName + "]", "colspan = 3", "class=center")}); + } else { + rv.add(new AbsCell[] {new TextCell("*** Data Unavailable ***", "colspan = 3", "class=center")}); + } + } + return null; + } + }); + } catch (Exception e) { + trans.error().log(e); + } finally { + tt.done(); + } + return new Cells(rv,msg); + } + } + +} diff --git a/auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/pages/NsInfoAction.java b/auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/pages/NsInfoAction.java new file mode 100644 index 00000000..4328653e --- /dev/null +++ b/auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/pages/NsInfoAction.java @@ -0,0 +1,158 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.gui.pages; + +import java.io.IOException; +import java.net.ConnectException; +import java.text.ParseException; + +import org.onap.aaf.auth.env.AuthzTrans; +import org.onap.aaf.auth.gui.AAF_GUI; +import org.onap.aaf.auth.gui.BreadCrumbs; +import org.onap.aaf.auth.gui.NamedCode; +import org.onap.aaf.auth.gui.Page; +import org.onap.aaf.cadi.CadiException; +import org.onap.aaf.cadi.client.Future; +import org.onap.aaf.cadi.client.Rcli; +import org.onap.aaf.cadi.client.Retryable; +import org.onap.aaf.misc.env.APIException; +import org.onap.aaf.misc.env.Env; +import org.onap.aaf.misc.env.Slot; +import org.onap.aaf.misc.env.TimeTaken; +import org.onap.aaf.misc.env.util.Chrono; +import org.onap.aaf.misc.xgen.Cache; +import org.onap.aaf.misc.xgen.DynamicCode; +import org.onap.aaf.misc.xgen.html.HTMLGen; + +import aaf.v2_0.CredRequest; + +public class NsInfoAction extends Page { + public NsInfoAction(final AAF_GUI gui, final Page ... breadcrumbs) throws APIException, IOException { + super(gui.env,"Onboard",PassChangeForm.HREF, PassChangeForm.fields, + new BreadCrumbs(breadcrumbs), + new NamedCode(true,"content") { + final Slot sID = gui.env.slot(PassChangeForm.NAME+'.'+PassChangeForm.fields[0]); + final Slot sCurrPass = gui.env.slot(PassChangeForm.NAME+'.'+PassChangeForm.fields[1]); + final Slot sPassword = gui.env.slot(PassChangeForm.NAME+'.'+PassChangeForm.fields[2]); + final Slot sPassword2 = gui.env.slot(PassChangeForm.NAME+'.'+PassChangeForm.fields[3]); + final Slot startDate = gui.env.slot(PassChangeForm.NAME+'.'+PassChangeForm.fields[4]); + + @Override + public void code(final Cache cache, final HTMLGen hgen) throws APIException, IOException { + cache.dynamic(hgen, new DynamicCode() { + @Override + public void code(final AAF_GUI gui, final AuthzTrans trans,final Cache cache, final HTMLGen hgen) throws APIException, IOException { + String id = trans.get(sID,null); + String currPass = trans.get(sCurrPass,null); + final String password = trans.get(sPassword,null); + String password2 = trans.get(sPassword2,null); + + // Run Validations + boolean fail = true; + + if (id==null || id.indexOf('@')<=0) { + hgen.p("Data Entry Failure: Please enter a valid ID, including domain."); + } else if(password == null || password2 == null || currPass == null) { + hgen.p("Data Entry Failure: Both Password Fields need entries."); + } else if(!password.equals(password2)) { + hgen.p("Data Entry Failure: Passwords do not match."); + } else { // everything else is checked by Server + final CredRequest cred = new CredRequest(); + cred.setId(id); + cred.setPassword(currPass); + try { + fail = gui.clientAsUser(trans.getUserPrincipal(), new Retryable() { + @Override + public Boolean code(Rcli client)throws CadiException, ConnectException, APIException { + TimeTaken tt = trans.start("Check Current Password",Env.REMOTE); + try { + Future fcr = client.create( // Note: Need "Post", because of hiding password in SSL Data + "/authn/validate", + gui.getDF(CredRequest.class), + cred + ); + boolean go; + boolean fail = true; + fcr.get(5000); + if(fcr.code() == 200) { + hgen.p("Current Password validated"); + go = true; + } else { + hgen.p(String.format("Invalid Current Password: %d %s",fcr.code(),fcr.body())); + go = false; + } + if(go) { + tt.done(); + tt = trans.start("AAF Change Password",Env.REMOTE); + try { + // Change over Cred to reset mode + cred.setPassword(password); + String start = trans.get(startDate, null); + if(start!=null) { + try { + cred.setStart(Chrono.timeStamp(Chrono.dateOnlyFmt.parse(start))); + } catch (ParseException e) { + throw new CadiException(e); + } + } + + fcr = client.create( + "/authn/cred", + gui.getDF(CredRequest.class), + cred + ); + + if(fcr.get(5000)) { + // Do Remote Call + hgen.p("New Password has been added."); + fail = false; + } else { + gui.writeError(trans, fcr, hgen, 0); + } + } finally { + tt.done(); + } + } + return fail; + } finally { + tt.done(); + } + } + }); + + } catch (Exception e) { + hgen.p("Unknown Error"); + e.printStackTrace(); + } + } + hgen.br(); + if(fail) { + hgen.incr("a",true,"href="+PassChangeForm.HREF+"?id="+id).text("Try again").end(); + } else { + hgen.incr("a",true,"href="+Home.HREF).text("Home").end(); + } + } + }); + } + }); + } +} diff --git a/auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/pages/NsInfoForm.java b/auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/pages/NsInfoForm.java new file mode 100644 index 00000000..173b9500 --- /dev/null +++ b/auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/pages/NsInfoForm.java @@ -0,0 +1,162 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.gui.pages; + +import static org.onap.aaf.misc.xgen.html.HTMLGen.A; +import static org.onap.aaf.misc.xgen.html.HTMLGen.TABLE; + +import java.io.IOException; +import java.net.ConnectException; +import java.util.List; + +import org.onap.aaf.auth.env.AuthzTrans; +import org.onap.aaf.auth.gui.AAF_GUI; +import org.onap.aaf.auth.gui.BreadCrumbs; +import org.onap.aaf.auth.gui.NamedCode; +import org.onap.aaf.auth.gui.Page; +import org.onap.aaf.cadi.CadiException; +import org.onap.aaf.cadi.client.Future; +import org.onap.aaf.cadi.client.Rcli; +import org.onap.aaf.cadi.client.Retryable; +import org.onap.aaf.misc.env.APIException; +import org.onap.aaf.misc.env.Env; +import org.onap.aaf.misc.env.Slot; +import org.onap.aaf.misc.env.TimeTaken; +import org.onap.aaf.misc.xgen.Cache; +import org.onap.aaf.misc.xgen.DynamicCode; +import org.onap.aaf.misc.xgen.Mark; +import org.onap.aaf.misc.xgen.html.HTMLGen; + +import aaf.v2_0.Nss; +import aaf.v2_0.Nss.Ns; + +public class NsInfoForm extends Page { + + // Package on purpose + static final String HREF = "/gui/onboard"; + static final String NAME = "Onboarding"; + static final String fields[] = {"ns","description","mots","owners","admins"}; + + public NsInfoForm(final AAF_GUI gui, final Page ... breadcrumbs) throws APIException, IOException { + super(gui.env,NAME,HREF, fields, + new BreadCrumbs(breadcrumbs), + new NamedCode(true,"content") { + + private final Slot sID = gui.env.slot(NsInfoForm.NAME+'.'+NsInfoForm.fields[0]); + @Override + public void code(final Cache cache, final HTMLGen hgen) throws APIException, IOException { + // p tags not closing right using .p() - causes issues in IE8 password form - so using leaf for the moment + hgen.leaf(HTMLGen.H2).text("Namespace Info").end() + .leaf("p").text("Hover over Fields for Tool Tips, or click ") + .leaf(A,"href="+gui.env.getProperty(AAF_URL_GUI_ONBOARD,"")).text("Here").end() + .text(" for more information") + .end() + .incr("form","method=post"); + Mark table = new Mark(TABLE); + hgen.incr(table); + cache.dynamic(hgen, new DynamicCode() { + @SuppressWarnings("unchecked") + @Override + public void code(final AAF_GUI gui, final AuthzTrans trans, final Cache cache, final HTMLGen hgen) throws APIException, IOException { + final String incomingID= trans.get(sID, ""); + final String[] info = new String[fields.length]; + final Object own_adm[] = new Object[2]; + for(int i=0;i0) { + TimeTaken tt = trans.start("AAF Namespace Info",Env.REMOTE); + try { + gui.clientAsUser(trans.getUserPrincipal(), new Retryable() { + @Override + public Void code(Rcli client) throws CadiException, ConnectException, APIException { + Future fn = client.read("/authz/nss/"+incomingID,gui.getDF(Nss.class)); + if(fn.get(AAF_GUI.TIMEOUT)) { + for(Ns ns : fn.value.getNs()) { + info[0]=ns.getName(); + info[1]=ns.getDescription(); + for(Ns.Attrib attr: ns.getAttrib()) { + switch(attr.getKey()) { + case "mots": + info[2]=attr.getValue(); + default: + } + } + own_adm[0]=ns.getResponsible(); + own_adm[1]=ns.getAdmin(); + } + } else { + trans.error().log(fn.body()); + } + return null; + } + }); + } catch (Exception e) { + trans.error().log("Unable to access AAF for NS Info",incomingID); + e.printStackTrace(); + } finally { + tt.done(); + } + } + hgen.input(fields[0],"Namespace",false,"value="+info[0],"title=AAF Namespace") + .input(fields[1],"Description*",true,"value="+info[1],"title=Full Application Name, Tool Name or Group") + .input(fields[2],"MOTS ID",false,"value="+info[2],"title=MOTS ID if this is an Application, and has MOTS"); + Mark endTD = new Mark(),endTR=new Mark(); + // Owners + hgen.incr(endTR,HTMLGen.TR) + .incr(endTD,HTMLGen.TD) + .leaf("label","for="+fields[3]).text("Responsible Party") + .end(endTD) + .incr(endTD,HTMLGen.TD) + .tagOnly("input","id="+fields[3],"title=Owner of App, must be an Non-Bargained Employee"); + if(own_adm[0]!=null) { + for(String s : (List)own_adm[0]) { + hgen.incr("label",true).text(s).end(); + } + } + hgen.end(endTR); + + // Admins + hgen.incr(endTR,HTMLGen.TR) + .incr(endTD,HTMLGen.TD) + .leaf("label","for="+fields[4]).text("Administrators") + .end(endTD) + .incr(endTD,HTMLGen.TD) + .tagOnly("input","id="+fields[4],"title=Admins may be employees, contractors or mechIDs"); + if(own_adm[1]!=null) { + for(String s : (List)own_adm[1]) { + hgen.incr(HTMLGen.P,true).text(s).end(); + } + } + hgen.end(endTR) + .end(); + } + }); + hgen.end(); + hgen.tagOnly("input", "type=submit", "value=Submit") + .end(); + + } + }); + } + +} diff --git a/auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/pages/NssShow.java b/auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/pages/NssShow.java new file mode 100644 index 00000000..02aedc5a --- /dev/null +++ b/auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/pages/NssShow.java @@ -0,0 +1,142 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.gui.pages; + +import java.io.IOException; +import java.net.ConnectException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; + +import org.onap.aaf.auth.env.AuthzEnv; +import org.onap.aaf.auth.env.AuthzTrans; +import org.onap.aaf.auth.gui.AAF_GUI; +import org.onap.aaf.auth.gui.BreadCrumbs; +import org.onap.aaf.auth.gui.Page; +import org.onap.aaf.auth.gui.Table; +import org.onap.aaf.auth.gui.Table.Cells; +import org.onap.aaf.auth.gui.table.AbsCell; +import org.onap.aaf.auth.gui.table.RefCell; +import org.onap.aaf.auth.gui.table.TableData; +import org.onap.aaf.cadi.CadiException; +import org.onap.aaf.cadi.client.Future; +import org.onap.aaf.cadi.client.Rcli; +import org.onap.aaf.cadi.client.Retryable; +import org.onap.aaf.misc.env.APIException; +import org.onap.aaf.misc.env.Env; +import org.onap.aaf.misc.env.Slot; +import org.onap.aaf.misc.env.TimeTaken; + +import aaf.v2_0.Nss; +import aaf.v2_0.Nss.Ns; + +public class NssShow extends Page { + public static final String HREF = "/gui/ns"; + + public NssShow(final AAF_GUI gui, final Page ... breadcrumbs) throws APIException, IOException { + super(gui.env, "MyNamespaces",HREF, NO_FIELDS, + new BreadCrumbs(breadcrumbs), + new Table("Namespaces I administer",gui.env.newTransNoAvg(),new Model(true,"Administrator",gui.env), + "class=std", "style=display: inline-block; width: 45%; margin: 10px;"), + new Table("Namespaces I own",gui.env.newTransNoAvg(),new Model(false,"Owner",gui.env), + "class=std", "style=display: inline-block; width: 45%; margin: 10px;")); + } + + private static class Model extends TableData { + private String[] headers; + private String privilege = null; + public final Slot sNssByUser; + private boolean isAdmin; + + public Model(boolean admin, String privilege,AuthzEnv env) { + super(); + headers = new String[] {privilege}; + this.privilege = privilege; + isAdmin = admin; + sNssByUser = env.slot("NSS_SHOW_MODEL_DATA"); + } + + @Override + public String[] headers() { + return headers; + } + + @Override + public Cells get(final AuthzTrans trans, final AAF_GUI gui) { + ArrayList rv = new ArrayList(); + List nss = trans.get(sNssByUser, null); + if(nss==null) { + TimeTaken tt = trans.start("AAF Nss by User for " + privilege,Env.REMOTE); + try { + nss = gui.clientAsUser(trans.getUserPrincipal(), new Retryable>() { + @Override + public List code(Rcli client) throws CadiException, ConnectException, APIException { + List nss = null; + Future fp = client.read("/authz/nss/either/" + trans.user(),gui.getDF(Nss.class)); + if(fp.get(AAF_GUI.TIMEOUT)) { + TimeTaken tt = trans.start("Load Data for " + privilege, Env.SUB); + try { + if(fp.value!=null) { + nss = fp.value.getNs(); + Collections.sort(nss, new Comparator() { + public int compare(Ns ns1, Ns ns2) { + return ns1.getName().compareToIgnoreCase(ns2.getName()); + } + }); + trans.put(sNssByUser,nss); + } + } finally { + tt.done(); + } + }else { + gui.writeError(trans, fp, null,0); + } + return nss; + } + }); + } catch (Exception e) { + trans.error().log(e); + } finally { + tt.done(); + } + } + + if(nss!=null) { + for(Ns n : nss) { + if((isAdmin && !n.getAdmin().isEmpty()) + || (!isAdmin && !n.getResponsible().isEmpty())) { + AbsCell[] sa = new AbsCell[] { + new RefCell(n.getName(),NsDetail.HREF + +"?ns="+n.getName(),false), + }; + rv.add(sa); + } + } + } + + return new Cells(rv,null); + } + } + + +} diff --git a/auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/pages/PassChangeAction.java b/auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/pages/PassChangeAction.java new file mode 100644 index 00000000..d0d03a7a --- /dev/null +++ b/auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/pages/PassChangeAction.java @@ -0,0 +1,211 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.gui.pages; + +import java.io.IOException; +import java.net.ConnectException; +import java.text.ParseException; +import java.util.GregorianCalendar; + +import org.onap.aaf.auth.cmd.AAFcli; +import org.onap.aaf.auth.cmd.user.Cred; +import org.onap.aaf.auth.env.AuthzTrans; +import org.onap.aaf.auth.gui.AAF_GUI; +import org.onap.aaf.auth.gui.BreadCrumbs; +import org.onap.aaf.auth.gui.NamedCode; +import org.onap.aaf.auth.gui.Page; +import org.onap.aaf.auth.org.Organization; +import org.onap.aaf.auth.org.OrganizationException; +import org.onap.aaf.auth.org.OrganizationFactory; +import org.onap.aaf.cadi.CadiException; +import org.onap.aaf.cadi.LocatorException; +import org.onap.aaf.cadi.client.Future; +import org.onap.aaf.cadi.client.Rcli; +import org.onap.aaf.cadi.client.Retryable; +import org.onap.aaf.misc.env.APIException; +import org.onap.aaf.misc.env.Env; +import org.onap.aaf.misc.env.Slot; +import org.onap.aaf.misc.env.TimeTaken; +import org.onap.aaf.misc.env.util.Chrono; +import org.onap.aaf.misc.xgen.Cache; +import org.onap.aaf.misc.xgen.DynamicCode; +import org.onap.aaf.misc.xgen.html.HTMLGen; + +import aaf.v2_0.CredRequest; +import aaf.v2_0.Users; + +public class PassChangeAction extends Page { + + public PassChangeAction(final AAF_GUI gui, final Page ... breadcrumbs) throws APIException, IOException { + super(gui.env,PassChangeForm.NAME,PassChangeForm.HREF, PassChangeForm.fields, + new BreadCrumbs(breadcrumbs), + new NamedCode(true,"content") { + final Slot sID = gui.env.slot(PassChangeForm.NAME+'.'+PassChangeForm.fields[0]); + final Slot sCurrPass = gui.env.slot(PassChangeForm.NAME+'.'+PassChangeForm.fields[1]); + final Slot sPassword = gui.env.slot(PassChangeForm.NAME+'.'+PassChangeForm.fields[2]); + final Slot sPassword2 = gui.env.slot(PassChangeForm.NAME+'.'+PassChangeForm.fields[3]); + final Slot startDate = gui.env.slot(PassChangeForm.NAME+'.'+PassChangeForm.fields[4]); + final Slot sNS = gui.env.slot(PassChangeForm.NAME+'.'+PassChangeForm.fields[5]); + + @Override + public void code(final Cache cache, final HTMLGen hgen) throws APIException, IOException { + cache.dynamic(hgen, new DynamicCode() { + @Override + public void code(final AAF_GUI gui, final AuthzTrans trans,final Cache cache, final HTMLGen hgen) throws APIException, IOException { + final String id = trans.get(sID,null); + final String currPass = trans.get(sCurrPass,null); + final String password = trans.get(sPassword,null); + final String password2 = trans.get(sPassword2,null); + final String ns = trans.get(sNS, null); + + // Run Validations + boolean fail = true; + + if (id==null || id.indexOf('@')<=0) { + hgen.p("Data Entry Failure: Please enter a valid ID, including domain."); + } else if(password == null || password2 == null) { + hgen.p("Data Entry Failure: Both Password Fields need entries."); + } else if(!password.equals(password2)) { + hgen.p("Data Entry Failure: Passwords do not match."); + } else { // everything else is checked by Server + final CredRequest cred = new CredRequest(); + cred.setId(id); + cred.setPassword("".equals(currPass)?null:currPass); + try { + fail = gui.clientAsUser(trans.getUserPrincipal(), new Retryable() { + @Override + public Boolean code(Rcli client)throws CadiException, ConnectException, APIException { + boolean fail = true; + boolean go = false; + try { + Organization org = OrganizationFactory.obtain(trans.env(), id); + if(org!=null) { + go = PassChangeForm.skipCurrent(trans, org.getIdentity(trans, id)); + } + } catch(OrganizationException e) { + trans.error().log(e); + } + + if(cred.getPassword()==null) { + try { + if(!go) { + go=gui.clientAsUser(trans.getUserPrincipal(), new Retryable() { + @Override + public Boolean code(Rcli client) throws CadiException, ConnectException, APIException { + Future fc = client.read("/authn/creds/id/"+id,gui.getDF(Users.class)); + if(fc.get(AAFcli.timeout())) { + GregorianCalendar now = new GregorianCalendar(); + for(aaf.v2_0.Users.User u : fc.value.getUser()) { + if(u.getType()<10 && u.getExpires().toGregorianCalendar().after(now)) { + return false; // an existing, non expired, password type exists + } + } + return true; // no existing, no expired password + } else { + if(fc.code()==404) { // not found... + return true; + } else { + trans.error().log(gui.aafCon.readableErrMsg(fc)); + } + } + return false; + } + }); + } + if(!go) { + hgen.p("Current Password required").br(); + } + } catch (LocatorException e) { + trans.error().log(e); + } + + } else { + TimeTaken tt = trans.start("Check Current Password",Env.REMOTE); + try { + // Note: Need "Post", because of hiding password in SSL Data + Future fcr = client.create("/authn/validate",gui.getDF(CredRequest.class),cred); + fcr.get(5000); + if(fcr.code() == 200) { + hgen.p("Current Password validated").br(); + go = true; + } else { + hgen.p(Cred.ATTEMPT_FAILED_SPECIFICS_WITHELD).br(); + trans.info().log("Failed Validation",fcr.code(),fcr.body()); + go = false; + } + } finally { + tt.done(); + } + } + if(go) { + TimeTaken tt = trans.start("AAF Change Password",Env.REMOTE); + try { + // Change over Cred to reset mode + cred.setPassword(password); + String start = trans.get(startDate, null); + if(start!=null) { + try { + cred.setStart(Chrono.timeStamp(Chrono.dateOnlyFmt.parse(start))); + } catch (ParseException e) { + throw new CadiException(e); + } + } + + Future fcr = gui.clientAsUser(trans.getUserPrincipal()).create("/authn/cred",gui.getDF(CredRequest.class),cred); + if(fcr.get(AAFcli.timeout())) { + // Do Remote Call + hgen.p("New Password has been added. The previous one is still valid until Expiration."); + fail = false; + } else { + hgen.p(Cred.ATTEMPT_FAILED_SPECIFICS_WITHELD).br(); + trans.info().log("Failed Validation",fcr.code(),fcr.body()); + } + } finally { + tt.done(); + } + } + return fail; + } + + }); + } catch (Exception e) { + hgen.p("Unknown Error"); + e.printStackTrace(); + } + + } + hgen.br(); + if(fail) { + hgen.incr(HTMLGen.A,true,"class=greenbutton","href="+PassChangeForm.HREF+"?id="+id).text("Try again").end(); + } else { + if(ns==null) { + hgen.incr(HTMLGen.A,true,"class=greenbutton","href="+Home.HREF).text("Back").end(); + } else { + hgen.incr(HTMLGen.A,true,"class=greenbutton","href="+CredDetail.HREF+"?id="+id+"&ns="+ns).text("Back").end(); + } + } + } + }); + } + }); + } +} diff --git a/auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/pages/PassChangeForm.java b/auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/pages/PassChangeForm.java new file mode 100644 index 00000000..897796d6 --- /dev/null +++ b/auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/pages/PassChangeForm.java @@ -0,0 +1,205 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.gui.pages; + +import static org.onap.aaf.misc.xgen.html.HTMLGen.TABLE; + +import java.io.IOException; +import java.net.ConnectException; +import java.util.GregorianCalendar; + +import org.onap.aaf.auth.cmd.AAFcli; +import org.onap.aaf.auth.env.AuthzTrans; +import org.onap.aaf.auth.gui.AAF_GUI; +import org.onap.aaf.auth.gui.BreadCrumbs; +import org.onap.aaf.auth.gui.NamedCode; +import org.onap.aaf.auth.gui.Page; +import org.onap.aaf.auth.org.Organization; +import org.onap.aaf.auth.org.OrganizationException; +import org.onap.aaf.auth.org.OrganizationFactory; +import org.onap.aaf.auth.org.Organization.Identity; +import org.onap.aaf.cadi.CadiException; +import org.onap.aaf.cadi.LocatorException; +import org.onap.aaf.cadi.client.Future; +import org.onap.aaf.cadi.client.Rcli; +import org.onap.aaf.cadi.client.Retryable; +import org.onap.aaf.misc.env.APIException; +import org.onap.aaf.misc.env.Slot; +import org.onap.aaf.misc.xgen.Cache; +import org.onap.aaf.misc.xgen.DynamicCode; +import org.onap.aaf.misc.xgen.Mark; +import org.onap.aaf.misc.xgen.html.HTMLGen; + +import aaf.v2_0.Users; + +public class PassChangeForm extends Page { + // Package on purpose + static final String HREF = "/gui/passwd"; + static final String NAME = "PassChange"; + static final String fields[] = {"id","current","password","password2","startDate","ns"}; + + public PassChangeForm(final AAF_GUI gui, final Page ... breadcrumbs) throws APIException, IOException { + super(gui.env,NAME,HREF, fields, + new BreadCrumbs(breadcrumbs), + new NamedCode(true,NAME) { + private final Slot sID = gui.env.slot(PassChangeForm.NAME+'.'+PassChangeForm.fields[0]); + @Override + public void code(final Cache cache, final HTMLGen hgen) throws APIException, IOException { + + // p tags not closing right using .p() - causes issues in IE8 password form - so using leaf for the moment + hgen.incr(HTMLGen.H4,true,"style=margin: 0em 0em .4em 0em") + .text("You are adding a New Password in the AAF System.") + .end(); + + Mark form = new Mark(); + hgen.incr(form,"form","method=post"); + + Mark table = new Mark(TABLE); + hgen.incr(table); + + cache.dynamic(hgen, new DynamicCode() { + @Override + public void code(final AAF_GUI gui, final AuthzTrans trans, final Cache cache, final HTMLGen hgen) throws APIException, IOException { + String incomingID= trans.get(sID, ""); + boolean skipCurrent = false; + if(incomingID.length()>0) { + try { + Organization org = OrganizationFactory.obtain(trans.env(), incomingID); + if(org==null) { + hgen.incr(HTMLGen.H4,"style=color:red;").text("Error: There is no supported company for ").text(incomingID).end(); + } else { + Identity user = org.getIdentity(trans, incomingID); + if(user==null) { + int at = incomingID.indexOf('@'); + hgen.incr(HTMLGen.H4,"style=color:red;").text("Error: You are not the sponsor of '").text(at<0?incomingID:incomingID.substring(0,at)) + .text("' defined at ").text(org.getName()).end(); + incomingID = ""; + } else { + // Owners/or the IDs themselves are allowed to reset password without previous one + skipCurrent=skipCurrent(trans, user); + + if(!skipCurrent) { + final String id = incomingID; + try { + skipCurrent=gui.clientAsUser(trans.getUserPrincipal(), new Retryable() { + @Override + public Boolean code(Rcli client) throws CadiException, ConnectException, APIException { + Future fc = client.read("/authn/creds/id/"+id,gui.getDF(Users.class)); + if(fc.get(AAFcli.timeout())) { + GregorianCalendar now = new GregorianCalendar(); + for(aaf.v2_0.Users.User u : fc.value.getUser()) { + if(u.getType()<10 && u.getType()>=1 && u.getExpires().toGregorianCalendar().after(now)) { + return false; // an existing, non expired, password type exists + } + } + return true; // no existing, no expired password + } else { + if(fc.code()==404) { // not found... + return true; + } else { + trans.error().log(gui.aafCon.readableErrMsg(fc)); + } + } + return false; + } + }); + } catch (LocatorException | CadiException e) { + trans.error().log(e); + } + } + } + } + } catch (OrganizationException e) { + hgen.incr(HTMLGen.H4,"style=color:red;").text("Error: ") + .text(e.getMessage()).end(); + } + } + + hgen.input(fields[0],"ID*",true,"value="+incomingID,(incomingID.length()==0?"":"readonly")); + if(!skipCurrent) { + hgen.input(fields[1],"Current Password*",true,"type=password"); + } + if(skipCurrent) { + hgen.input(fields[1],"",false,"type=hidden", "value=").end(); + } + + hgen.input(fields[2],"New Password*",true, "type=password") + .input(fields[3], "Reenter New Password*",true, "type=password") + // .input(fields[3],"Start Date",false,"type=date", "value="+ + // Chrono.dateOnlyFmt.format(new Date(System.currentTimeMillis())) + // ) + .end(table); + + } + + }); + hgen.tagOnly("input", "type=submit", "value=Submit") + .end(form) + .br() + .p("All AAF Passwords continue to be valid until their listed expiration dates. ", + "This allows you to migrate services to this new password until the old ones expire.").br().br() + .p("Note: You must be an Admin of the Namespace where the MechID is defined.").br() + ; + + Mark div = hgen.divID("passwordRules"); + cache.dynamic(hgen, new DynamicCode() { + @Override + public void code(final AAF_GUI gui, final AuthzTrans trans, final Cache cache, final HTMLGen hgen) throws APIException, IOException { + try { + Organization org = OrganizationFactory.obtain(trans.env(),trans.getUserPrincipal().getName()); + if(org!=null) { + hgen.incr(HTMLGen.H4).text("Password Rules for ").text(org.getName()).end() + .incr(HTMLGen.UL); + for(String line : org.getPasswordRules()) { + hgen.leaf(HTMLGen.LI).text(line).end(); + } + hgen.end(); + } + } catch (OrganizationException e) { + hgen.p("No Password Rules can be found for company of ID ",trans.getUserPrincipal().getName()).br(); + } + } + }); + hgen.end(div); + } + } + ); + } + + // Package on Purpose + static boolean skipCurrent(AuthzTrans trans, Identity user) throws OrganizationException { + if(user!=null) { + // Should this be an abstractable Policy? + String tuser = trans.user(); + if(user.fullID().equals(trans.user())) { + return true; + } else { + Identity manager = user.responsibleTo(); + if(tuser.equals(user.fullID()) || manager.isFound()) { + return true; + } + } + } + return false; + } + +} diff --git a/auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/pages/PassDeleteAction.java b/auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/pages/PassDeleteAction.java new file mode 100644 index 00000000..49daf022 --- /dev/null +++ b/auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/pages/PassDeleteAction.java @@ -0,0 +1,88 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.gui.pages; + +import java.io.IOException; +import java.net.ConnectException; + +import org.onap.aaf.auth.cmd.AAFcli; +import org.onap.aaf.auth.env.AuthzTrans; +import org.onap.aaf.auth.gui.AAF_GUI; +import org.onap.aaf.auth.gui.BreadCrumbs; +import org.onap.aaf.auth.gui.Page; +import org.onap.aaf.auth.gui.SlotCode; +import org.onap.aaf.cadi.CadiException; +import org.onap.aaf.cadi.LocatorException; +import org.onap.aaf.cadi.client.Future; +import org.onap.aaf.cadi.client.Rcli; +import org.onap.aaf.cadi.client.Retryable; +import org.onap.aaf.misc.env.APIException; +import org.onap.aaf.misc.xgen.Cache; +import org.onap.aaf.misc.xgen.DynamicCode; +import org.onap.aaf.misc.xgen.html.HTMLGen; + +import aaf.v2_0.CredRequest; + +public class PassDeleteAction extends Page { + public static final String NAME = "PassDeleteAction"; + public static final String HREF = "/gui/passdelete"; + private static enum Params{id,date,ns,type}; + + public PassDeleteAction(final AAF_GUI gui, final Page ... breadcrumbs) throws APIException, IOException { + super(gui.env,NAME,HREF,Params.values(), + new BreadCrumbs(breadcrumbs), + new SlotCode(true,gui.env,NAME,Params.values()) { + @Override + public void code(final Cache cache, final HTMLGen hgen) throws APIException, IOException { + cache.dynamic(hgen, new DynamicCode() { + @Override + public void code(final AAF_GUI gui, final AuthzTrans trans,final Cache cache, final HTMLGen hgen) throws APIException, IOException { + final CredRequest cr = new CredRequest(); + cr.setId(get(trans,Params.id, "")); + cr.setType(Integer.parseInt(get(trans,Params.type, "0"))); + cr.setEntry(get(trans,Params.date,"1960-01-01")); + try { + String err = gui.clientAsUser(trans.getUserPrincipal(), new Retryable() { + @Override + public String code(Rcli client) throws CadiException, ConnectException, APIException { + Future fcr = client.delete("/authn/cred", gui.getDF(CredRequest.class),cr); + if(!fcr.get(AAFcli.timeout())) { + return gui.aafCon.readableErrMsg(fcr); + } + return null; + } + }); + if(err==null) { + hgen.p("Password " + cr.getId() + ", " + cr.getEntry() + " is Deleted"); + } else { + hgen.p(err); + } + } catch (LocatorException | CadiException e) { + throw new APIException(e); + } + } + }); + } + } + ); + } +} diff --git a/auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/pages/PendingRequestsShow.java b/auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/pages/PendingRequestsShow.java new file mode 100644 index 00000000..e55d803c --- /dev/null +++ b/auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/pages/PendingRequestsShow.java @@ -0,0 +1,193 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.gui.pages; + +import java.io.IOException; +import java.net.ConnectException; +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; +import java.util.UUID; + +import org.onap.aaf.auth.env.AuthzTrans; +import org.onap.aaf.auth.gui.AAF_GUI; +import org.onap.aaf.auth.gui.BreadCrumbs; +import org.onap.aaf.auth.gui.NamedCode; +import org.onap.aaf.auth.gui.Page; +import org.onap.aaf.auth.gui.Table; +import org.onap.aaf.auth.gui.Table.Cells; +import org.onap.aaf.auth.gui.table.AbsCell; +import org.onap.aaf.auth.gui.table.RefCell; +import org.onap.aaf.auth.gui.table.TableData; +import org.onap.aaf.auth.gui.table.TextCell; +import org.onap.aaf.cadi.CadiException; +import org.onap.aaf.cadi.client.Future; +import org.onap.aaf.cadi.client.Rcli; +import org.onap.aaf.cadi.client.Retryable; +import org.onap.aaf.misc.env.APIException; +import org.onap.aaf.misc.env.Env; +import org.onap.aaf.misc.env.TimeTaken; +import org.onap.aaf.misc.xgen.Cache; +import org.onap.aaf.misc.xgen.DynamicCode; +import org.onap.aaf.misc.xgen.html.HTMLGen; + +import aaf.v2_0.Approval; +import aaf.v2_0.Approvals; + +public class PendingRequestsShow extends Page { + public static final String HREF = "/gui/myrequests"; + public static final String NAME = "MyRequests"; + static final String WEBPHONE = "http://webphone.att.com/cgi-bin/webphones.pl?id="; + private static DateFormat createdDF = new SimpleDateFormat("yyyy-MM-dd"); + + public PendingRequestsShow(final AAF_GUI gui, final Page ... breadcrumbs) throws APIException, IOException { + super(gui.env, NAME,HREF, NO_FIELDS, + new BreadCrumbs(breadcrumbs), + new NamedCode(true,"expedite") { + @Override + public void code(final Cache cache, final HTMLGen hgen) throws APIException, IOException { + cache.dynamic(hgen, new DynamicCode() { + @Override + public void code(final AAF_GUI gui, final AuthzTrans trans, final Cache cache, final HTMLGen hgen) throws APIException, IOException { + hgen + .leaf("p", "class=expedite_request").text("These are your submitted Requests that are awaiting Approval. ") + .br() + .text("To Expedite a Request: ") + .leaf("a","href=#expedite_directions","onclick=divVisibility('expedite_directions');") + .text("Click Here").end() + .divID("expedite_directions", "style=display:none"); + hgen + .incr(HTMLGen.OL) + .incr(HTMLGen.LI) + .leaf("a","href="+ApprovalForm.HREF+"?user="+trans.user(), "id=userApprove") + .text("Copy This Link") + .end() + .end() + .incr(HTMLGen.LI) + .text("Send it to the Approver Listed") + .end() + .end() + .text("NOTE: Using this link, the Approver will only see your requests. You only need to send this link once!") + .end() + .end(); + } + }); + } + }, + new Table("Pending Requests",gui.env.newTransNoAvg(),new Model(), "class=std") + ); + + + } + + /** + * Implement the Table Content for Requests by User + * + * @author Jeremiah + * + */ + private static class Model extends TableData { + private static final String CSP_ATT_COM = "@csp.att.com"; + final long NUM_100NS_INTERVALS_SINCE_UUID_EPOCH = 0x01b21dd213814000L; + private static final String[] headers = new String[] {"Request Date","Status","Memo","Approver"}; + + @Override + public String[] headers() { + return headers; + } + + @Override + public Cells get(final AuthzTrans trans, final AAF_GUI gui) { + final ArrayList rv = new ArrayList(); + try { + gui.clientAsUser(trans.getUserPrincipal(), new Retryable() { + @Override + public Void code(Rcli client)throws CadiException, ConnectException, APIException { + TimeTaken tt = trans.start("AAF Get Approvals by User",Env.REMOTE); + try { + Future fa = client.read("/authz/approval/user/"+trans.user(),gui.getDF(Approvals.class)); + if(fa.get(5000)) { + tt.done(); + tt = trans.start("Load Data", Env.SUB); + if(fa.value!=null) { + List approvals = fa.value.getApprovals(); + Collections.sort(approvals, new Comparator() { + @Override + public int compare(Approval a1, Approval a2) { + UUID id1 = UUID.fromString(a1.getId()); + UUID id2 = UUID.fromString(a2.getId()); + return id1.timestamp()<=id2.timestamp()?1:-1; + } + }); + + String prevTicket = null; + for(Approval a : approvals) { + String approver = a.getApprover(); + String approverShort = approver.substring(0,approver.indexOf('@')); + + AbsCell tsCell = null; + String ticket = a.getTicket(); + if (ticket==null || ticket.equals(prevTicket)) { + tsCell = AbsCell.Null; + } else { + UUID id = UUID.fromString(a.getId()); + tsCell = new RefCell(createdDF.format((id.timestamp() - NUM_100NS_INTERVALS_SINCE_UUID_EPOCH)/10000), + RequestDetail.HREF + "?ticket=" + ticket,false); + prevTicket = ticket; + } + + AbsCell approverCell = null; + if (approver.endsWith(CSP_ATT_COM)) { + approverCell = new RefCell(approver, WEBPHONE + approverShort,true); + } else { + approverCell = new TextCell(approver); + } + AbsCell[] sa = new AbsCell[] { + tsCell, + new TextCell(a.getStatus()), + new TextCell(a.getMemo()), + approverCell + }; + rv.add(sa); + } + } + } else { + gui.writeError(trans, fa, null, 0); + } + } finally { + tt.done(); + } + + + return null; + } + }); + } catch (Exception e) { + trans.error().log(e); + } + return new Cells(rv,null); + } + } +} diff --git a/auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/pages/PermDetail.java b/auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/pages/PermDetail.java new file mode 100644 index 00000000..822d0bf4 --- /dev/null +++ b/auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/pages/PermDetail.java @@ -0,0 +1,160 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.gui.pages; + +import java.io.IOException; +import java.net.ConnectException; +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.jetty.http.HttpStatus; +import org.onap.aaf.auth.env.AuthzEnv; +import org.onap.aaf.auth.env.AuthzTrans; +import org.onap.aaf.auth.gui.AAF_GUI; +import org.onap.aaf.auth.gui.BreadCrumbs; +import org.onap.aaf.auth.gui.Page; +import org.onap.aaf.auth.gui.Table; +import org.onap.aaf.auth.gui.Table.Cells; +import org.onap.aaf.auth.gui.table.AbsCell; +import org.onap.aaf.auth.gui.table.RefCell; +import org.onap.aaf.auth.gui.table.TableData; +import org.onap.aaf.auth.gui.table.TextCell; +import org.onap.aaf.auth.validation.Validator; +import org.onap.aaf.cadi.CadiException; +import org.onap.aaf.cadi.client.Future; +import org.onap.aaf.cadi.client.Rcli; +import org.onap.aaf.cadi.client.Retryable; +import org.onap.aaf.misc.env.APIException; +import org.onap.aaf.misc.env.Env; +import org.onap.aaf.misc.env.Slot; +import org.onap.aaf.misc.env.TimeTaken; + +import aaf.v2_0.Perm; +import aaf.v2_0.Perms; + +/** + * Detail Page for Permissions + * + * @author Jonathan + * + */ +public class PermDetail extends Page { + public static final String HREF = "/gui/permdetail"; + public static final String NAME = "PermDetail"; + private static final String BLANK = ""; + + public PermDetail(final AAF_GUI gui, Page ... breadcrumbs) throws APIException, IOException { + super(gui.env, NAME, HREF, new String[] {"type","instance","action"}, + new BreadCrumbs(breadcrumbs), + new Table("Permission Details",gui.env.newTransNoAvg(),new Model(gui.env),"class=detail") + ); + } + + /** + * Implement the table content for Permissions Detail + * + * @author Jonathan + * + */ + private static class Model extends TableData { + private Slot type, instance, action; + public Model(AuthzEnv env) { + type = env.slot(NAME+".type"); + instance = env.slot(NAME+".instance"); + action = env.slot(NAME+".action"); + } + + public Cells get(final AuthzTrans trans, final AAF_GUI gui) { + final String pType = trans.get(type, null); + final String pInstance = trans.get(instance, null); + final String pAction = trans.get(action, null); + Validator v = new Validator(); + v.permType(pType) + .permInstance(pInstance) + .permAction(pAction); + + if(v.err()) { + trans.warn().printf("Error in PermDetail Request: %s", v.errs()); + return Cells.EMPTY; + } + final ArrayList rv = new ArrayList(); + rv.add(new AbsCell[]{new TextCell("Type:"),new TextCell(pType)}); + rv.add(new AbsCell[]{new TextCell("Instance:"),new TextCell(pInstance)}); + rv.add(new AbsCell[]{new TextCell("Action:"),new TextCell(pAction)}); + try { + gui.clientAsUser(trans.getUserPrincipal(), new Retryable() { + @Override + public Void code(Rcli client)throws CadiException, ConnectException, APIException { + TimeTaken tt = trans.start("AAF Perm Details",Env.REMOTE); + try { + Future fp= client.read("/authz/perms/"+pType + '/' + pInstance + '/' + pAction,gui.getDF(Perms.class)); + + if(fp.get(AAF_GUI.TIMEOUT)) { + tt.done(); + tt = trans.start("Load Data", Env.SUB); + List ps = fp.value.getPerm(); + if(!ps.isEmpty()) { + Perm perm = fp.value.getPerm().get(0); + String desc = (perm.getDescription()!=null?perm.getDescription():BLANK); + rv.add(new AbsCell[]{new TextCell("Description:"),new TextCell(desc)}); + boolean first=true; + for(String r : perm.getRoles()) { + if(first){ + first=false; + rv.add(new AbsCell[] { + new TextCell("Associated Roles:"), + new TextCell(r) + }); + } else { + rv.add(new AbsCell[] { + AbsCell.Null, + new TextCell(r) + }); + } + } + } + String historyLink = PermHistory.HREF + + "?type=" + pType + "&instance=" + pInstance + "&action=" + pAction; + + rv.add(new AbsCell[] {new RefCell("See History",historyLink,false)}); + } else { + rv.add(new AbsCell[] {new TextCell( + fp.code()==HttpStatus.NOT_FOUND_404? + "*** Implicit Permission ***": + "*** Data Unavailable ***" + )}); + } + } finally { + tt.done(); + } + + return null; + } + }); + } catch (Exception e) { + e.printStackTrace(); + } + return new Cells(rv,null); + } + } +} + \ No newline at end of file diff --git a/auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/pages/PermGrantAction.java b/auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/pages/PermGrantAction.java new file mode 100644 index 00000000..dd854660 --- /dev/null +++ b/auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/pages/PermGrantAction.java @@ -0,0 +1,135 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.gui.pages; + +import java.io.IOException; +import java.net.ConnectException; + +import org.onap.aaf.auth.env.AuthzTrans; +import org.onap.aaf.auth.gui.AAF_GUI; +import org.onap.aaf.auth.gui.BreadCrumbs; +import org.onap.aaf.auth.gui.NamedCode; +import org.onap.aaf.auth.gui.Page; +import org.onap.aaf.cadi.CadiException; +import org.onap.aaf.cadi.client.Future; +import org.onap.aaf.cadi.client.Rcli; +import org.onap.aaf.cadi.client.Retryable; +import org.onap.aaf.misc.env.APIException; +import org.onap.aaf.misc.env.Env; +import org.onap.aaf.misc.env.Slot; +import org.onap.aaf.misc.env.TimeTaken; +import org.onap.aaf.misc.xgen.Cache; +import org.onap.aaf.misc.xgen.DynamicCode; +import org.onap.aaf.misc.xgen.html.HTMLGen; + +import aaf.v2_0.Pkey; +import aaf.v2_0.RolePermRequest; + +public class PermGrantAction extends Page { + + + public PermGrantAction(final AAF_GUI gui, final Page ... breadcrumbs) throws APIException, IOException { + super(gui.env,PermGrantForm.NAME, PermGrantForm.HREF, PermGrantForm.fields, + new BreadCrumbs(breadcrumbs), + new NamedCode(true,"content") { + final Slot sType = gui.env.slot(PermGrantForm.NAME+'.'+PermGrantForm.fields[0]); + final Slot sInstance = gui.env.slot(PermGrantForm.NAME+'.'+PermGrantForm.fields[1]); + final Slot sAction = gui.env.slot(PermGrantForm.NAME+'.'+PermGrantForm.fields[2]); + final Slot sRole = gui.env.slot(PermGrantForm.NAME+'.'+PermGrantForm.fields[3]); + + @Override + public void code(final Cache cache, final HTMLGen hgen) throws APIException, IOException { + cache.dynamic(hgen, new DynamicCode() { + @Override + public void code(final AAF_GUI gui, final AuthzTrans trans,final Cache cache, final HTMLGen hgen) throws APIException, IOException { + + String type = trans.get(sType,null); + String instance = trans.get(sInstance,null); + String action = trans.get(sAction,null); + String role = trans.get(sRole,null); + + String lastPage = PermGrantForm.HREF + + "?type=" + type + "&instance=" + instance + "&action=" + action; + + // Run Validations + boolean fail = true; + + TimeTaken tt = trans.start("AAF Grant Permission to Role",Env.REMOTE); + try { + + final RolePermRequest grantReq = new RolePermRequest(); + Pkey pkey = new Pkey(); + pkey.setType(type); + pkey.setInstance(instance); + pkey.setAction(action); + grantReq.setPerm(pkey); + grantReq.setRole(role); + + fail = gui.clientAsUser(trans.getUserPrincipal(), new Retryable() { + @Override + public Boolean code(Rcli client) throws CadiException, ConnectException, APIException { + boolean fail = true; + Future fgrant = client.create( + "/authz/role/perm", + gui.getDF(RolePermRequest.class), + grantReq + ); + + if(fgrant.get(5000)) { + hgen.p("Permission has been granted to role."); + fail = false; + } else { + if (202==fgrant.code()) { + hgen.p("Permission Grant Request sent, but must be Approved before actualizing"); + fail = false; + } else { + gui.writeError(trans, fgrant, hgen, 0); + } + } + return fail; + } + }); + } catch (Exception e) { + hgen.p("Unknown Error"); + e.printStackTrace(); + } finally { + tt.done(); + } + + hgen.br(); + hgen.incr("a",true,"href="+lastPage); + if (fail) { + hgen.text("Try again"); + } else { + hgen.text("Grant this Permission to Another Role"); + } + hgen.end(); + hgen.js() + .text("alterLink('permgrant', '"+lastPage + "');") + .done(); + + } + }); + } + }); + } +} diff --git a/auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/pages/PermGrantForm.java b/auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/pages/PermGrantForm.java new file mode 100644 index 00000000..1c5bc4c1 --- /dev/null +++ b/auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/pages/PermGrantForm.java @@ -0,0 +1,157 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.gui.pages; + +import static org.onap.aaf.misc.xgen.html.HTMLGen.TABLE; + +import java.io.IOException; +import java.net.ConnectException; +import java.util.ArrayList; +import java.util.List; + +import org.onap.aaf.auth.env.AuthzTrans; +import org.onap.aaf.auth.gui.AAF_GUI; +import org.onap.aaf.auth.gui.BreadCrumbs; +import org.onap.aaf.auth.gui.NamedCode; +import org.onap.aaf.auth.gui.Page; +import org.onap.aaf.cadi.CadiException; +import org.onap.aaf.cadi.client.Future; +import org.onap.aaf.cadi.client.Rcli; +import org.onap.aaf.cadi.client.Retryable; +import org.onap.aaf.misc.env.APIException; +import org.onap.aaf.misc.env.Env; +import org.onap.aaf.misc.env.Slot; +import org.onap.aaf.misc.env.TimeTaken; +import org.onap.aaf.misc.xgen.Cache; +import org.onap.aaf.misc.xgen.DynamicCode; +import org.onap.aaf.misc.xgen.Mark; +import org.onap.aaf.misc.xgen.html.HTMLGen; + +import aaf.v2_0.Role; +import aaf.v2_0.Roles; + +public class PermGrantForm extends Page { + static final String HREF = "/gui/permgrant"; + static final String NAME = "Permission Grant"; + static final String fields[] = {"type","instance","action","role"}; + + public PermGrantForm(final AAF_GUI gui, final Page ... breadcrumbs) throws APIException, IOException { + super(gui.env,NAME,HREF, fields, + new BreadCrumbs(breadcrumbs), + new NamedCode(true,"content") { + @Override + public void code(final Cache cache, final HTMLGen hgen) throws APIException, IOException { + final Slot type = gui.env.slot(NAME+".type"); + final Slot instance = gui.env.slot(NAME+".instance"); + final Slot action = gui.env.slot(NAME+".action"); + final Slot role = gui.env.slot(NAME+".role"); + // p tags not closing right using .p() - causes issues in IE8 password form - so using leaf for the moment + hgen.leaf("p").text("Choose a role to grant to this permission").end() + .incr("form","method=post"); + Mark table = new Mark(TABLE); + hgen.incr(table); + cache.dynamic(hgen, new DynamicCode() { + @Override + public void code(final AAF_GUI gui, final AuthzTrans trans, final Cache cache, final HTMLGen hgen) throws APIException, IOException { + + Mark copyRoleJS = new Mark(); + hgen.js(copyRoleJS); + hgen.text("function copyRole(role) {"); + hgen.text("var txtRole = document.querySelector(\"#role\");"); +// hgen.text("if (role==;"); + hgen.text("txtRole.value=role;"); + hgen.text("}"); + hgen.end(copyRoleJS); + + String typeValue = trans.get(type, ""); + String instanceValue = trans.get(instance, ""); + String actionValue = trans.get(action, ""); + String roleValue = trans.get(role,null); + List myRoles = getMyRoles(gui, trans); + hgen + .input(fields[0],"Perm Type",true,"value="+typeValue,"disabled") + .input(fields[1],"Perm Instance",true,"value="+instanceValue,"disabled") + .input(fields[2],"Perm Action",true,"value="+actionValue,"disabled"); + + // select & options are not an input type, so we must create table row & cell tags + Mark selectRow = new Mark(); + hgen + .incr(selectRow, "tr") + .incr("td") + .incr("label", "for=myroles", "required").text("My Roles").end() + .end() + .incr("td") + .incr("select", "name=myroles", "id=myroles", "onchange=copyRole(this.value)") + .incr("option", "value=").text("Select one of my roles").end(); + for (String role : myRoles) { + hgen.incr("option", "value="+role).text(role).end(); + } + hgen + .incr("option", "value=").text("Other").end() + .end(selectRow); + if(roleValue==null) { + hgen.input(fields[3],"Role", true, "placeholder=or type a role here"); + } else { + hgen.input(fields[3],"Role",true, "value="+roleValue); + } + hgen.end(); + } + }); + hgen.end(); + hgen.tagOnly("input", "type=submit", "value=Submit") + .end(); + + } + }); + } + + private static List getMyRoles(final AAF_GUI gui, final AuthzTrans trans) { + final List myRoles = new ArrayList(); + try { + gui.clientAsUser(trans.getUserPrincipal(), new Retryable() { + @Override + public Void code(Rcli client) throws CadiException, ConnectException, APIException { + TimeTaken tt = trans.start("AAF get my roles",Env.REMOTE); + try { + Future fr = client.read("/authz/roles/user/"+trans.user(),gui.getDF(Roles.class)); + if(fr.get(5000)) { + tt.done(); + tt = trans.start("Load Data", Env.SUB); + if (fr.value != null) for (Role r : fr.value.getRole()) { + myRoles.add(r.getName()); + } + } else { + gui.writeError(trans, fr, null, 0); + } + } finally { + tt.done(); + } + return null; + } + }); + } catch (Exception e) { + e.printStackTrace(); + } + + return myRoles; + } +} diff --git a/auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/pages/PermHistory.java b/auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/pages/PermHistory.java new file mode 100644 index 00000000..45f8b22e --- /dev/null +++ b/auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/pages/PermHistory.java @@ -0,0 +1,243 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.gui.pages; + + +import java.io.IOException; +import java.net.ConnectException; +import java.util.ArrayList; +import java.util.Calendar; +import java.util.Comparator; +import java.util.List; + +import org.onap.aaf.auth.env.AuthzEnv; +import org.onap.aaf.auth.env.AuthzTrans; +import org.onap.aaf.auth.gui.AAF_GUI; +import org.onap.aaf.auth.gui.BreadCrumbs; +import org.onap.aaf.auth.gui.NamedCode; +import org.onap.aaf.auth.gui.Page; +import org.onap.aaf.auth.gui.Table; +import org.onap.aaf.auth.gui.Table.Cells; +import org.onap.aaf.auth.gui.table.AbsCell; +import org.onap.aaf.auth.gui.table.RefCell; +import org.onap.aaf.auth.gui.table.TableData; +import org.onap.aaf.auth.gui.table.TextCell; +import org.onap.aaf.cadi.CadiException; +import org.onap.aaf.cadi.client.Future; +import org.onap.aaf.cadi.client.Rcli; +import org.onap.aaf.cadi.client.Retryable; +import org.onap.aaf.misc.env.APIException; +import org.onap.aaf.misc.env.Env; +import org.onap.aaf.misc.env.Slot; +import org.onap.aaf.misc.env.TimeTaken; +import org.onap.aaf.misc.xgen.Cache; +import org.onap.aaf.misc.xgen.DynamicCode; +import org.onap.aaf.misc.xgen.html.HTMLGen; + +import aaf.v2_0.History; +import aaf.v2_0.History.Item; + + +public class PermHistory extends Page { + static final String NAME="PermHistory"; + static final String HREF = "/gui/permHistory"; + static final String FIELDS[] = {"type","instance","action","dates"}; + static final String WEBPHONE = "http://webphone.att.com/cgi-bin/webphones.pl?id="; + static enum Month { JANUARY, FEBRUARY, MARCH, APRIL, MAY, JUNE, JULY, + AUGUST, SEPTEMBER, OCTOBER, NOVEMBER, DECEMBER }; + + public PermHistory(final AAF_GUI gui, final Page ... breadcrumbs) throws APIException, IOException { + super(gui.env,NAME,HREF, FIELDS, + new BreadCrumbs(breadcrumbs), + new Table("History", gui.env.newTransNoAvg(),new Model(gui.env),"class=std"), + new NamedCode(true, "content") { + @Override + public void code(final Cache cache, final HTMLGen hgen) throws APIException, IOException { + final Slot sType = gui.env.slot(NAME+".type"); + final Slot sInstance = gui.env.slot(NAME+".instance"); + final Slot sAction = gui.env.slot(NAME+".action"); + cache.dynamic(hgen, new DynamicCode() { + @Override + public void code(final AAF_GUI gui, final AuthzTrans trans, final Cache cache, final HTMLGen hgen) throws APIException, IOException { + String type = trans.get(sType, null); + String instance = trans.get(sInstance,null); + String action = trans.get(sAction,null); + + // Use Javascript to make the table title more descriptive + hgen.js() + .text("var caption = document.querySelector(\".title\");") + .text("caption.innerHTML='History for Permission [ " + type + " ]';") + .done(); + + // Use Javascript to change Link Target to our last visited Detail page + String lastPage = PermDetail.HREF + "?type=" + type + + "&instance=" + instance + + "&action=" + action; + hgen.js() + .text("alterLink('permdetail', '"+lastPage + "');") + .done(); + + hgen.br(); + hgen.leaf("a", "href=#advanced_search", "onclick=divVisibility('advanced_search');").text("Advanced Search").end() + .divID("advanced_search", "style=display:none"); + hgen.incr("table"); + + addDateRow(hgen,"Start Date"); + addDateRow(hgen,"End Date"); + hgen.incr("tr").incr("td"); + hgen.tagOnly("input", "type=button","value=Get History", + "onclick=datesURL('"+HREF+"?type=" + type + + "&instance=" + instance + + "&action=" + action+"');"); + hgen.end().end(); + hgen.end(); + hgen.end(); + } + }); + } + } + + ); + + } + + private static void addDateRow(HTMLGen hgen, String s) { + hgen + .incr("tr") + .incr("td") + .incr("label", "for=month", "required").text(s+"*").end() + .end() + .incr("td") + .incr("select", "name=month"+s.substring(0, s.indexOf(' ')), "id=month"+s.substring(0, s.indexOf(' ')), "required") + .incr("option", "value=").text("Month").end(); + for (Month m : Month.values()) { + if (Calendar.getInstance().get(Calendar.MONTH) == m.ordinal()) { + hgen.incr("option", "selected", "value="+(m.ordinal()+1)).text(m.name()).end(); + } else { + hgen.incr("option", "value="+(m.ordinal()+1)).text(m.name()).end(); + } + } + hgen.end() + .end() + .incr("td") + .tagOnly("input","type=number","id=year"+s.substring(0, s.indexOf(' ')),"required", + "value="+Calendar.getInstance().get(Calendar.YEAR), "min=1900", + "max="+Calendar.getInstance().get(Calendar.YEAR), + "placeholder=Year").end() + .end(); + } + + /** + * Implement the Table Content for History + * + * @author Jeremiah + * + */ + private static class Model extends TableData { + private static final String CSP_ATT_COM = "@csp.att.com"; + private static final String[] headers = new String[] {"Date","User","Memo"}; + private Slot sType; + private Slot sDates; + + public Model(AuthzEnv env) { + sType = env.slot(NAME+".type"); + sDates = env.slot(NAME+".dates"); + } + + @Override + public String[] headers() { + return headers; + } + + @Override + public Cells get(final AuthzTrans trans, final AAF_GUI gui) { + final String oName = trans.get(sType,null); + final String oDates = trans.get(sDates,null); + + if(oName==null) { + return Cells.EMPTY; + } + + final ArrayList rv = new ArrayList(); + String msg = null; + try { + gui.clientAsUser(trans.getUserPrincipal(), new Retryable() { + @Override + public Void code(Rcli client) throws CadiException, ConnectException, APIException { + TimeTaken tt = trans.start("AAF Get History for Permission ["+oName+"]",Env.REMOTE); + try { + if (oDates != null) { + client.setQueryParams("yyyymm="+oDates); + } + Future fh = client.read( + "/authz/hist/perm/"+oName, + gui.getDF(History.class) + ); + + + if (fh.get(AAF_GUI.TIMEOUT)) { + tt.done(); + tt = trans.start("Load History Data", Env.SUB); + List histItems = fh.value.getItem(); + + java.util.Collections.sort(histItems, new Comparator() { + @Override + public int compare(Item o1, Item o2) { + return o2.getTimestamp().compare(o1.getTimestamp()); + } + }); + + for (Item i : histItems) { + String user = i.getUser(); + AbsCell userCell = (user.endsWith(CSP_ATT_COM)? + new RefCell(user,WEBPHONE + user.substring(0,user.indexOf('@')),true):new TextCell(user)); + + rv.add(new AbsCell[] { + new TextCell(i.getTimestamp().toGregorianCalendar().getTime().toString()), + userCell, + new TextCell(i.getMemo()) + }); + } + + } else { + if (fh.code()==403) { + rv.add(new AbsCell[] {new TextCell("You may not view History of Permission [" + oName + "]", "colspan = 3", "class=center")}); + } else { + rv.add(new AbsCell[] {new TextCell("*** Data Unavailable ***", "colspan = 3", "class=center")}); + } + } + } finally { + tt.done(); + } + + return null; + } + }); + + } catch (Exception e) { + trans.error().log(e); + } + return new Cells(rv,msg); + } + } + +} diff --git a/auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/pages/PermsShow.java b/auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/pages/PermsShow.java new file mode 100644 index 00000000..5f5c2874 --- /dev/null +++ b/auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/pages/PermsShow.java @@ -0,0 +1,121 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.gui.pages; + +import java.io.IOException; +import java.net.ConnectException; +import java.util.ArrayList; + +import org.onap.aaf.auth.env.AuthzTrans; +import org.onap.aaf.auth.gui.AAF_GUI; +import org.onap.aaf.auth.gui.BreadCrumbs; +import org.onap.aaf.auth.gui.Page; +import org.onap.aaf.auth.gui.Table; +import org.onap.aaf.auth.gui.Table.Cells; +import org.onap.aaf.auth.gui.table.AbsCell; +import org.onap.aaf.auth.gui.table.RefCell; +import org.onap.aaf.auth.gui.table.TableData; +import org.onap.aaf.auth.gui.table.TextCell; +import org.onap.aaf.cadi.CadiException; +import org.onap.aaf.cadi.client.Future; +import org.onap.aaf.cadi.client.Rcli; +import org.onap.aaf.cadi.client.Retryable; +import org.onap.aaf.misc.env.APIException; +import org.onap.aaf.misc.env.Env; +import org.onap.aaf.misc.env.TimeTaken; + +import aaf.v2_0.Perm; +import aaf.v2_0.Perms; + +/** + * Page content for My Permissions + * + * @author Jonathan + * + */ +public class PermsShow extends Page { + public static final String HREF = "/gui/myperms"; + + public PermsShow(final AAF_GUI gui, final Page ... breadcrumbs) throws APIException, IOException { + super(gui.env, "MyPerms",HREF, NO_FIELDS, + new BreadCrumbs(breadcrumbs), + new Table("Permissions",gui.env.newTransNoAvg(),new Model(), "class=std")); + } + + /** + * Implement the Table Content for Permissions by User + * + * @author Jonathan + * + */ + private static class Model extends TableData { + private static final String[] headers = new String[] {"Type","Instance","Action"}; + + @Override + public String[] headers() { + return headers; + } + + @Override + public Cells get(final AuthzTrans trans, final AAF_GUI gui) { + final ArrayList rv = new ArrayList(); + TimeTaken tt = trans.start("AAF Perms by User",Env.REMOTE); + try { + gui.clientAsUser(trans.getUserPrincipal(), new Retryable() { + @Override + public Void code(Rcli client) throws CadiException, ConnectException, APIException { + Future fp = client.read("/authz/perms/user/"+trans.user(), gui.getDF(Perms.class)); + if(fp.get(5000)) { + TimeTaken ttld = trans.start("Load Data", Env.SUB); + try { + if(fp.value!=null) { + for(Perm p : fp.value.getPerm()) { + AbsCell[] sa = new AbsCell[] { + new RefCell(p.getType(),PermDetail.HREF + +"?type="+p.getType() + +"&instance="+p.getInstance() + +"&action="+p.getAction(), + false), + new TextCell(p.getInstance()), + new TextCell(p.getAction()) + }; + rv.add(sa); + } + } else { + gui.writeError(trans, fp, null,0); + } + } finally { + ttld.done(); + } + } + return null; + } + }); + } catch (Exception e) { + trans.error().log(e); + } finally { + tt.done(); + } + return new Cells(rv,null); + } + } +} diff --git a/auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/pages/RequestDetail.java b/auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/pages/RequestDetail.java new file mode 100644 index 00000000..852bbd44 --- /dev/null +++ b/auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/pages/RequestDetail.java @@ -0,0 +1,190 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.gui.pages; + +import java.io.IOException; +import java.net.ConnectException; +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.UUID; + +import org.onap.aaf.auth.env.AuthzEnv; +import org.onap.aaf.auth.env.AuthzTrans; +import org.onap.aaf.auth.gui.AAF_GUI; +import org.onap.aaf.auth.gui.BreadCrumbs; +import org.onap.aaf.auth.gui.Page; +import org.onap.aaf.auth.gui.Table; +import org.onap.aaf.auth.gui.Table.Cells; +import org.onap.aaf.auth.gui.table.AbsCell; +import org.onap.aaf.auth.gui.table.RefCell; +import org.onap.aaf.auth.gui.table.TableData; +import org.onap.aaf.auth.gui.table.TextCell; +import org.onap.aaf.cadi.CadiException; +import org.onap.aaf.cadi.client.Future; +import org.onap.aaf.cadi.client.Rcli; +import org.onap.aaf.cadi.client.Retryable; +import org.onap.aaf.misc.env.APIException; +import org.onap.aaf.misc.env.Env; +import org.onap.aaf.misc.env.Slot; +import org.onap.aaf.misc.env.TimeTaken; + +import aaf.v2_0.Approval; +import aaf.v2_0.Approvals; + +public class RequestDetail extends Page { + public static final String HREF = "/gui/requestdetail"; + public static final String NAME = "RequestDetail"; + private static final String DATE_TIME_FORMAT = "yyyy-MM-dd HH:mm:ss"; + public static final String[] FIELDS = {"ticket"}; + + public RequestDetail(final AAF_GUI gui, Page ... breadcrumbs) throws APIException, IOException { + super(gui.env, NAME, HREF, FIELDS, + new BreadCrumbs(breadcrumbs), + new Table("Request Details",gui.env.newTransNoAvg(),new Model(gui.env),"class=detail") + ); + } + + /** + * Implement the table content for Request Detail + * + * @author Jeremiah + * + */ + private static class Model extends TableData { + static final String WEBPHONE = "http://webphone.att.com/cgi-bin/webphones.pl?id="; + private static final String CSP_ATT_COM = "@csp.att.com"; + final long NUM_100NS_INTERVALS_SINCE_UUID_EPOCH = 0x01b21dd213814000L; + private Slot sTicket; + public Model(AuthzEnv env) { + sTicket = env.slot(NAME+".ticket"); + } + + @Override + public Cells get(final AuthzTrans trans, final AAF_GUI gui) { + Cells rv=Cells.EMPTY; + final String ticket = trans.get(sTicket, null); + if(ticket!=null) { + try { + rv = gui.clientAsUser(trans.getUserPrincipal(), new Retryable() { + @Override + public Cells code(Rcli client) throws CadiException, ConnectException, APIException { + TimeTaken tt = trans.start("AAF Approval Details",Env.REMOTE); + ArrayList rv = new ArrayList(); + try { + Future fa = client.read( + "/authz/approval/ticket/"+ticket, + gui.getDF(Approvals.class) + ); + + if(fa.get(AAF_GUI.TIMEOUT)) { + if (!trans.user().equals(fa.value.getApprovals().get(0).getUser())) { + return Cells.EMPTY; + } + tt.done(); + tt = trans.start("Load Data", Env.SUB); + boolean first = true; + for ( Approval approval : fa.value.getApprovals()) { + AbsCell[] approverLine = new AbsCell[4]; + // only print common elements once + if (first) { + DateFormat createdDF = new SimpleDateFormat(DATE_TIME_FORMAT); + UUID id = UUID.fromString(approval.getId()); + + rv.add(new AbsCell[]{new TextCell("Ticket ID:"),new TextCell(approval.getTicket(),"colspan=3")}); + rv.add(new AbsCell[]{new TextCell("Memo:"),new TextCell(approval.getMemo(),"colspan=3")}); + rv.add(new AbsCell[]{new TextCell("Requested On:"), + new TextCell(createdDF.format((id.timestamp() - NUM_100NS_INTERVALS_SINCE_UUID_EPOCH)/10000),"colspan=3") + }); + rv.add(new AbsCell[]{new TextCell("Operation:"),new TextCell(decodeOp(approval.getOperation()),"colspan=3")}); + String user = approval.getUser(); + if (user.endsWith(CSP_ATT_COM)) { + rv.add(new AbsCell[]{new TextCell("User:"), + new RefCell(user,WEBPHONE + user.substring(0, user.indexOf("@")),true,"colspan=3")}); + } else { + rv.add(new AbsCell[]{new TextCell("User:"),new TextCell(user,"colspan=3")}); + } + + // headers for listing each approver + rv.add(new AbsCell[]{new TextCell(" ","colspan=4","class=blank_line")}); + rv.add(new AbsCell[]{AbsCell.Null, + new TextCell("Approver","class=bold"), + new TextCell("Type","class=bold"), + new TextCell("Status","class=bold")}); + approverLine[0] = new TextCell("Approvals:"); + + first = false; + } else { + approverLine[0] = AbsCell.Null; + } + + String approver = approval.getApprover(); + String approverShort = approver.substring(0,approver.indexOf('@')); + + if (approver.endsWith(CSP_ATT_COM)) { + approverLine[1] = new RefCell(approver, WEBPHONE + approverShort,true); + } else { + approverLine[1] = new TextCell(approval.getApprover()); + } + + String type = approval.getType(); + if ("owner".equalsIgnoreCase(type)) { + type = "resource owner"; + } + + approverLine[2] = new TextCell(type); + approverLine[3] = new TextCell(approval.getStatus()); + rv.add(approverLine); + + } + } else { + rv.add(new AbsCell[] {new TextCell("*** Data Unavailable ***")}); + } + } finally { + tt.done(); + } + return new Cells(rv,null); + } + }); + } catch (Exception e) { + trans.error().log(e); + } + } + return rv; + } + + private String decodeOp(String operation) { + if ("C".equalsIgnoreCase(operation)) { + return "Create"; + } else if ("D".equalsIgnoreCase(operation)) { + return "Delete"; + } else if ("U".equalsIgnoreCase(operation)) { + return "Update"; + } else if ("G".equalsIgnoreCase(operation)) { + return "Grant"; + } else if ("UG".equalsIgnoreCase(operation)) { + return "Un-Grant"; + } + return operation; + } + } +} diff --git a/auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/pages/RoleDetail.java b/auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/pages/RoleDetail.java new file mode 100644 index 00000000..37526b86 --- /dev/null +++ b/auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/pages/RoleDetail.java @@ -0,0 +1,295 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.gui.pages; + +import java.io.IOException; +import java.net.ConnectException; +import java.util.ArrayList; +import java.util.List; + +import org.onap.aaf.auth.env.AuthzEnv; +import org.onap.aaf.auth.env.AuthzTrans; +import org.onap.aaf.auth.gui.AAF_GUI; +import org.onap.aaf.auth.gui.BreadCrumbs; +import org.onap.aaf.auth.gui.Page; +import org.onap.aaf.auth.gui.Table; +import org.onap.aaf.auth.gui.Table.Cells; +import org.onap.aaf.auth.gui.table.AbsCell; +import org.onap.aaf.auth.gui.table.CheckBoxCell; +import org.onap.aaf.auth.gui.table.CheckBoxCell.ALIGN; +import org.onap.aaf.auth.gui.table.RefCell; +import org.onap.aaf.auth.gui.table.TableData; +import org.onap.aaf.auth.gui.table.TextCell; +import org.onap.aaf.auth.gui.table.TextInputCell; +import org.onap.aaf.auth.validation.Validator; +import org.onap.aaf.cadi.CadiException; +import org.onap.aaf.cadi.aaf.AAFPermission; +import org.onap.aaf.cadi.client.Future; +import org.onap.aaf.cadi.client.Rcli; +import org.onap.aaf.cadi.client.Retryable; +import org.onap.aaf.misc.env.APIException; +import org.onap.aaf.misc.env.Env; +import org.onap.aaf.misc.env.Slot; +import org.onap.aaf.misc.env.TimeTaken; +import org.onap.aaf.misc.env.util.Chrono; +import org.onap.aaf.misc.xgen.Cache; +import org.onap.aaf.misc.xgen.Mark; +import org.onap.aaf.misc.xgen.html.HTMLGen; + +import aaf.v2_0.Pkey; +import aaf.v2_0.Role; +import aaf.v2_0.Roles; +import aaf.v2_0.UserRole; +import aaf.v2_0.UserRoles; + +/** + * Detail Page for Permissions + * + * @author Jonathan + * + */ +public class RoleDetail extends Page { + public static final String HREF = "/gui/roledetail"; + public static final String NAME = "RoleDetail"; + private static final String BLANK = ""; + + public RoleDetail(final AAF_GUI gui, Page ... breadcrumbs) throws APIException, IOException { + super(gui.env, NAME, HREF, new String[] {"role","ns"}, + new BreadCrumbs(breadcrumbs), + new Table("Role Details",gui.env.newTransNoAvg(), + new Model(gui.env),"class=detail") + ); + } + + /** + * Implement the table content for Permissions Detail + * + * @author Jonathan + * + */ + private static class Model extends TableData { + private Slot sRoleName,sRole,sUserRole,sMayWrite,sMayApprove,sMark,sNS; + public Model(AuthzEnv env) { + sRoleName = env.slot(NAME+".role"); + sRole = env.slot(NAME+".data.role"); + sUserRole = env.slot(NAME+".data.userrole"); + sMayWrite = env.slot(NAME+"mayWrite"); + sMayApprove = env.slot(NAME+"mayApprove"); + sMark = env.slot(NAME+"mark"); + sNS = env.slot(NAME+".ns"); + } + + /* (non-Javadoc) + * @see org.onap.aaf.auth.gui.table.TableData#prefix(org.onap.aaf.misc.xgen.html.State, com.att.inno.env.Trans, org.onap.aaf.misc.xgen.Cache, org.onap.aaf.misc.xgen.html.HTMLGen) + */ + @Override + public void prefix(final AAF_GUI gui, final AuthzTrans trans, final Cache cache, final HTMLGen hgen) { + final String pRole = trans.get(sRoleName, null); + Validator v = new Validator(); + v.role(pRole); + if(v.err()) { + trans.warn().printf("Error in PermDetail Request: %s", v.errs()); + return; + } + + + try { + gui.clientAsUser(trans.getUserPrincipal(), new Retryable() { + @Override + public Boolean code(Rcli client) throws CadiException, ConnectException, APIException { + TimeTaken tt = trans.start("AAF Role Details",Env.REMOTE); + try { + Future fr = client.read("/authz/roles/"+pRole+"?ns",gui.getDF(Roles.class)); + Future fur = client.read("/authz/userRoles/role/"+pRole,gui.getDF(UserRoles.class)); + if(fr.get(AAF_GUI.TIMEOUT)) { + Role role = fr.value.getRole().get(0); + trans.put(sRole, role); + Boolean mayWrite = trans.fish(new AAFPermission(role.getNs()+".access",":role:"+role.getName(),"write")); + trans.put(sMayWrite,mayWrite); + Boolean mayApprove = trans.fish(new AAFPermission(role.getNs()+".access",":role:"+role.getName(),"approve")); + trans.put(sMayApprove, mayApprove); + + if(mayWrite || mayApprove) { + Mark js = new Mark(); + Mark fn = new Mark(); + hgen.js(js) + .function(fn,"touchedDesc") + .li("d=document.getElementById('descText');", + "if (d.orig == undefined ) {", + " d.orig = d.value;", + " d.addEventListener('keyup',changedDesc);", + " d.removeEventListener('keypress',touchedDesc);", + "}").end(fn) + .function(fn,"changedDesc") + .li( + "dcb=document.getElementById('descCB');", + "d=document.getElementById('descText');", + "dcb.checked= (d.orig != d.value)" + ).end(fn) + .end(js); + + Mark mark = new Mark(); + hgen.incr(mark,"form","method=post"); + trans.put(sMark, mark); + } + } else { + trans.error().printf("Error calling AAF for Roles in GUI, Role Detail %d: %s",fr.code(),fr.body()); + return false; + } + + if(fur.get(AAF_GUI.TIMEOUT)) { + trans.put(sUserRole, fur.value.getUserRole()); + } else { + trans.error().printf("Error calling AAF for UserRoles in GUI, Role Detail %d: %s",fr.code(),fr.body()); + return false; + } + + return true; + } finally { + tt.done(); + } + } + }); + } catch (Exception e) { + trans.error().log(e); + } + } + + @Override + public Cells get(final AuthzTrans trans, final AAF_GUI gui) { + final String pRole = trans.get(sRoleName, null); + final Role role = trans.get(sRole,null); + ArrayList rv = new ArrayList(); + + if(role!=null) { + boolean mayWrite = trans.get(sMayWrite, false); + boolean mayApprove = trans.get(sMayApprove, false); + + String desc = (role.getDescription()!=null?role.getDescription():BLANK); + rv.add(new AbsCell[]{ + new TextCell("Role:","width=45%"), + new TextCell(pRole)}); + if(mayWrite) { + rv.add(new AbsCell[]{ + new TextCell("Description:","width=45%"), + new TextInputCell("description","textInput",desc,"id=descText","onkeypress=touchedDesc()"), + new CheckBoxCell("desc",ALIGN.left, "changed","id=descCB", "style=visibility: hidden"), + }); + rv.add(AbsCell.HLINE); + rv.add(new AbsCell[] { + new TextCell("Associated Permissions:","width=25%"), + new TextCell("UnGrant","width=10%"), + }); + } else { + rv.add(new AbsCell[]{ + new TextCell("Description:","width=45%"), + new TextCell(desc)}); + } + boolean protectedRole = role.getName().endsWith(".owner") || + role.getName().endsWith(".admin"); + boolean first = true; + for(Pkey r : role.getPerms()) { + String key=r.getType() + '|' + r.getInstance() + '|' + r.getAction(); + if(mayWrite) { + rv.add(new AbsCell[] { + AbsCell.Null, + protectedRole && r.getType().endsWith(".access") + ?new TextCell("protected","class=protected") // Do not allow ungranting of basic NS perms + :new CheckBoxCell("perm.ungrant",key), + new TextCell("","width=10%"), + new TextCell(key) + }); + } else { + if(first) { + rv.add(new AbsCell[] { + new TextCell("Associated Permissions:","width=45%"), + new TextCell(key) + }); + first=false; + } else { + rv.add(new AbsCell[] { + AbsCell.Null, + new TextCell(key) + }); + } + } + } + + if(mayApprove) { + rv.add(AbsCell.HLINE); + + // + rv.add(new AbsCell[] { + new TextCell("Users in Role:","width=25%"), + new TextCell("Delete","width=10%"), + new TextCell("Extend","width=10%") + }); + + List userroles = trans.get(sUserRole,null); + if(userroles!=null) { + for(UserRole ur : userroles) { + String tag = "userrole"; + + rv.add(new AbsCell[] { + AbsCell.Null, + new CheckBoxCell(tag+".delete", ur.getUser()), + new CheckBoxCell(tag+".extend", ur.getUser()), + new TextCell(ur.getUser()), + new TextCell(Chrono.dateOnlyStamp(ur.getExpires()) + )}); + } + } + } + + // History + rv.add(new AbsCell[] { + new RefCell("See History",RoleHistory.HREF + "?role=" + pRole,false) + }); + } else { + rv.add(new AbsCell[]{ + new TextCell("Role:"), + new TextCell(pRole)}); + + rv.add(new AbsCell[] {new TextCell("*** Data Unavailable ***")}); + } + return new Cells(rv, null); + } + + /* (non-Javadoc) + * @see org.onap.aaf.auth.gui.table.TableData#postfix(org.onap.aaf.misc.xgen.html.State, com.att.inno.env.Trans, org.onap.aaf.misc.xgen.Cache, org.onap.aaf.misc.xgen.html.HTMLGen) + */ + @Override + public void postfix(AAF_GUI state, AuthzTrans trans, final Cache cache, final HTMLGen hgen) { + final Mark mark = trans.get(sMark, null); + if(mark!=null) { + hgen.tagOnly("input", "type=submit", "value=Submit"); + final String pNS = trans.get(sNS, null); + if(pNS!=null && pNS.length()>0) { + hgen.leaf(mark,HTMLGen.A,"href="+NsDetail.HREF+"?ns="+pNS,"class=greenbutton").text("Back").end(mark); + } + hgen.end(mark); + } + + } + } +} + \ No newline at end of file diff --git a/auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/pages/RoleDetailAction.java b/auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/pages/RoleDetailAction.java new file mode 100644 index 00000000..f2d2c01f --- /dev/null +++ b/auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/pages/RoleDetailAction.java @@ -0,0 +1,188 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.gui.pages; + +import java.io.IOException; +import java.net.ConnectException; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; + +import javax.servlet.http.HttpServletRequest; + +import org.onap.aaf.auth.env.AuthzTrans; +import org.onap.aaf.auth.gui.AAF_GUI; +import org.onap.aaf.auth.gui.BreadCrumbs; +import org.onap.aaf.auth.gui.NamedCode; +import org.onap.aaf.auth.gui.Page; +import org.onap.aaf.auth.gui.table.TableData; +import org.onap.aaf.cadi.CadiException; +import org.onap.aaf.cadi.client.Future; +import org.onap.aaf.cadi.client.Rcli; +import org.onap.aaf.cadi.client.Retryable; +import org.onap.aaf.cadi.util.Split; +import org.onap.aaf.misc.env.APIException; +import org.onap.aaf.misc.env.Env; +import org.onap.aaf.misc.env.Slot; +import org.onap.aaf.misc.env.TimeTaken; +import org.onap.aaf.misc.xgen.Cache; +import org.onap.aaf.misc.xgen.DynamicCode; +import org.onap.aaf.misc.xgen.html.HTMLGen; + +import aaf.v2_0.Pkey; +import aaf.v2_0.RolePermRequest; +import aaf.v2_0.RoleRequest; + +public class RoleDetailAction extends Page { + public RoleDetailAction(final AAF_GUI gui, final Page ... breadcrumbs) throws APIException, IOException { + super(gui.env,RoleDetail.NAME, RoleDetail.HREF, TableData.headers, + new BreadCrumbs(breadcrumbs), + new NamedCode(true,"content") { + final Slot sReq = gui.env.slot(AAF_GUI.HTTP_SERVLET_REQUEST); + + @Override + public void code(final Cache cache, final HTMLGen hgen) throws APIException, IOException { + cache.dynamic(hgen, new DynamicCode() { + @Override + public void code(final AAF_GUI gui, final AuthzTrans trans,final Cache cache, final HTMLGen hgen) throws APIException, IOException { + final HttpServletRequest req = trans.get(sReq, null); + final String role = getSingleParam(req,"role"); + if(role==null) { + hgen.text("Parameter 'role' is required").end(); + } else { + // Run Validations +// boolean fail; + try { + /*fail =*/ gui.clientAsUser(trans.getUserPrincipal(), new Retryable() { + @Override + public Boolean code(Rcli client) throws CadiException, ConnectException, APIException { + List ltf = new ArrayList(); + String text; + Map pm = (Map)req.getParameterMap(); + for(final Entry es : pm.entrySet()) { + for(final String v : es.getValue()) { + TimeTaken tt = null; + try { + switch(es.getKey()) { + case "desc": // Check box set + String desc = getSingleParam(req, "description"); + if(desc!=null) { + text = "Setting Description on " + role + " to " + desc; + tt = trans.start(text, Env.REMOTE); + RoleRequest rr = new RoleRequest(); + rr.setName(role); + rr.setDescription(desc); + ltf.add(new TypedFuture(ActionType.desc, text, + client.update("/authz/role", + gui.getDF(RoleRequest.class),rr + ))); + } + break; + case "perm.ungrant": + text = "Ungranting Permission '" + v + "' from '" + role + '\''; + tt = trans.start(text, Env.REMOTE); + String[] pf = Split.splitTrim('|', v); + if(pf.length==3) { + Pkey perm = new Pkey(); + perm.setType(pf[0]); + perm.setInstance(pf[1]); + perm.setAction(pf[2]); + RolePermRequest rpr = new RolePermRequest(); + rpr.setPerm(perm); + rpr.setRole(role); + ltf.add(new TypedFuture(ActionType.ungrant,text, + client.delete("/authz/role/" + role + "/perm", + gui.getDF(RolePermRequest.class),rpr + ))); + } else { + hgen.p(v + " is not a valid Perm for ungranting"); + } + break; + case "userrole.extend": + text = "Extending " + v + " in " + role; + tt = trans.start(text, Env.REMOTE); + ltf.add(new TypedFuture(ActionType.extendUR,text, + client.update("/authz/userRole/extend/" + v + '/' + role))); + break; + case "userrole.delete": + text = "Deleting " + v + " from " + role; + tt = trans.start(text, Env.REMOTE); + ltf.add(new TypedFuture(ActionType.deleteUR,text, + client.delete("/authz/userRole/" + v + '/' + role, Void.class))); + break; + + default: +// System.out.println(es.getKey() + "=" + v); + } + } finally { + if(tt!=null) { + tt.done(); + tt=null; + } + } + } + } + + if(ltf.isEmpty()) { + hgen.p("No Changes"); + } else { + for(TypedFuture tf : ltf) { + if(tf.future.get(5000)) { + hgen.p("Success: " + tf.text); + } else { + // Note: if handling of special Error codes is required, use + // switch(tf.type) { + // } + hgen.p(tf.text); + gui.writeError(trans, tf.future, hgen,4); + } + } + } + return true; + } + }); + } catch (Exception e) { + hgen.p("Unknown Error"); + e.printStackTrace(); + } + } + } + + }); + } + }); + } + + enum ActionType {desc, ungrant, deleteUR, extendUR}; + private static class TypedFuture { +// public final ActionType type; + public final Future future; + public final String text; + + public TypedFuture(ActionType type, String text, Future future) { +// this.type = type; + this.future = future; + this.text = text; + } + } +} diff --git a/auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/pages/RoleHistory.java b/auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/pages/RoleHistory.java new file mode 100644 index 00000000..e80a5917 --- /dev/null +++ b/auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/pages/RoleHistory.java @@ -0,0 +1,228 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.gui.pages; + + +import java.io.IOException; +import java.net.ConnectException; +import java.util.ArrayList; +import java.util.Calendar; +import java.util.Comparator; +import java.util.List; + +import org.onap.aaf.auth.env.AuthzEnv; +import org.onap.aaf.auth.env.AuthzTrans; +import org.onap.aaf.auth.gui.AAF_GUI; +import org.onap.aaf.auth.gui.BreadCrumbs; +import org.onap.aaf.auth.gui.NamedCode; +import org.onap.aaf.auth.gui.Page; +import org.onap.aaf.auth.gui.Table; +import org.onap.aaf.auth.gui.Table.Cells; +import org.onap.aaf.auth.gui.table.AbsCell; +import org.onap.aaf.auth.gui.table.RefCell; +import org.onap.aaf.auth.gui.table.TableData; +import org.onap.aaf.auth.gui.table.TextCell; +import org.onap.aaf.cadi.CadiException; +import org.onap.aaf.cadi.client.Future; +import org.onap.aaf.cadi.client.Rcli; +import org.onap.aaf.cadi.client.Retryable; +import org.onap.aaf.misc.env.APIException; +import org.onap.aaf.misc.env.Env; +import org.onap.aaf.misc.env.Slot; +import org.onap.aaf.misc.env.TimeTaken; +import org.onap.aaf.misc.xgen.Cache; +import org.onap.aaf.misc.xgen.DynamicCode; +import org.onap.aaf.misc.xgen.html.HTMLGen; + +import aaf.v2_0.History; +import aaf.v2_0.History.Item; + + +public class RoleHistory extends Page { + static final String NAME="RoleHistory"; + static final String HREF = "/gui/roleHistory"; + static final String FIELDS[] = {"role","dates"}; + static final String WEBPHONE = "http://webphone.att.com/cgi-bin/webphones.pl?id="; + static enum Month { JANUARY, FEBRUARY, MARCH, APRIL, MAY, JUNE, JULY, + AUGUST, SEPTEMBER, OCTOBER, NOVEMBER, DECEMBER }; + + public RoleHistory(final AAF_GUI gui, final Page ... breadcrumbs) throws APIException, IOException { + super(gui.env,NAME,HREF, FIELDS, + new BreadCrumbs(breadcrumbs), + new Table("History", gui.env.newTransNoAvg(),new Model(gui.env),"class=std"), + new NamedCode(true, "content") { + @Override + public void code(final Cache cache, final HTMLGen hgen) throws APIException, IOException { + final Slot role = gui.env.slot(NAME+".role"); + cache.dynamic(hgen, new DynamicCode() { + @Override + public void code(final AAF_GUI gui, final AuthzTrans trans, final Cache cache, final HTMLGen hgen) throws APIException, IOException { + String obRole = trans.get(role, null); + + // Use Javascript to make the table title more descriptive + hgen.js() + .text("var caption = document.querySelector(\".title\");") + .text("caption.innerHTML='History for Role [ " + obRole + " ]';") + .done(); + + // Use Javascript to change Link Target to our last visited Detail page + String lastPage = RoleDetail.HREF + "?role=" + obRole; + hgen.js() + .text("alterLink('roledetail', '"+lastPage + "');") + .done(); + + hgen.br(); + hgen.leaf("a", "href=#advanced_search","onclick=divVisibility('advanced_search');").text("Advanced Search").end() + .divID("advanced_search", "style=display:none"); + hgen.incr("table"); + + addDateRow(hgen,"Start Date"); + addDateRow(hgen,"End Date"); + hgen.incr("tr").incr("td"); + hgen.tagOnly("input", "type=button","value=Get History", + "onclick=datesURL('"+HREF+"?role=" + obRole+"');"); + hgen.end().end(); + hgen.end(); + hgen.end(); + } + }); + } + } + + ); + + } + + private static void addDateRow(HTMLGen hgen, String s) { + hgen + .incr("tr") + .incr("td") + .incr("label", "for=month", "required").text(s+"*").end() + .end() + .incr("td") + .incr("select", "name=month"+s.substring(0, s.indexOf(' ')), "id=month"+s.substring(0, s.indexOf(' ')), "required") + .incr("option", "value=").text("Month").end(); + for (Month m : Month.values()) { + if (Calendar.getInstance().get(Calendar.MONTH) == m.ordinal()) { + hgen.incr("option", "selected", "value="+(m.ordinal()+1)).text(m.name()).end(); + } else { + hgen.incr("option", "value="+(m.ordinal()+1)).text(m.name()).end(); + } + } + hgen.end() + .end() + .incr("td") + .tagOnly("input","type=number","id=year"+s.substring(0, s.indexOf(' ')),"required", + "value="+Calendar.getInstance().get(Calendar.YEAR), "min=1900", + "max="+Calendar.getInstance().get(Calendar.YEAR), + "placeholder=Year").end() + .end(); + } + + + /** + * Implement the Table Content for History + * + * @author Jeremiah + * + */ + private static class Model extends TableData { + private static final String CSP_ATT_COM = "@csp.att.com"; + private static final String[] headers = new String[] {"Date","User","Memo"}; + private Slot role; + private Slot dates; + + public Model(AuthzEnv env) { + role = env.slot(NAME+".role"); + dates = env.slot(NAME+".dates"); + } + + @Override + public String[] headers() { + return headers; + } + + @Override + public Cells get(final AuthzTrans trans, final AAF_GUI gui) { + final String oName = trans.get(role,null); + final String oDates = trans.get(dates,null); + + Cells rv = Cells.EMPTY; + if(oName!=null) { + + try { + rv = gui.clientAsUser(trans.getUserPrincipal(), new Retryable() { + @Override + public Cells code(Rcli client) throws CadiException, ConnectException, APIException { + ArrayList rv = new ArrayList(); + TimeTaken tt = trans.start("AAF Get History for Namespace ["+oName+"]",Env.REMOTE); + String msg = null; + try { + if (oDates != null) { + client.setQueryParams("yyyymm="+oDates); + } + Future fh = client.read("/authz/hist/role/"+oName,gui.getDF(History.class)); + if (fh.get(AAF_GUI.TIMEOUT)) { + tt.done(); + tt = trans.start("Load History Data", Env.SUB); + List histItems = fh.value.getItem(); + + java.util.Collections.sort(histItems, new Comparator() { + @Override + public int compare(Item o1, Item o2) { + return o2.getTimestamp().compare(o1.getTimestamp()); + } + }); + + for (Item i : histItems) { + String user = i.getUser(); + AbsCell userCell = (user.endsWith(CSP_ATT_COM)? + new RefCell(user,WEBPHONE + user.substring(0,user.indexOf('@')),false):new TextCell(user)); + + rv.add(new AbsCell[] { + new TextCell(i.getTimestamp().toGregorianCalendar().getTime().toString()), + userCell, + new TextCell(i.getMemo()) + }); + } + } else { + if (fh.code()==403) { + rv.add(new AbsCell[] {new TextCell("You may not view History of Permission [" + oName + "]", "colspan = 3", "class=center")}); + } else { + rv.add(new AbsCell[] {new TextCell("*** Data Unavailable ***", "colspan = 3", "class=center")}); + } + } + } finally { + tt.done(); + } + return new Cells(rv,msg); + } + }); + } catch (Exception e) { + trans.error().log(e); + } + } + return rv; + } + } + +} diff --git a/auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/pages/RolesShow.java b/auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/pages/RolesShow.java new file mode 100644 index 00000000..071666d0 --- /dev/null +++ b/auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/pages/RolesShow.java @@ -0,0 +1,144 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.gui.pages; + +import java.io.IOException; +import java.net.ConnectException; +import java.text.SimpleDateFormat; +import java.util.ArrayList; + +import org.onap.aaf.auth.env.AuthzTrans; +import org.onap.aaf.auth.gui.AAF_GUI; +import org.onap.aaf.auth.gui.BreadCrumbs; +import org.onap.aaf.auth.gui.Page; +import org.onap.aaf.auth.gui.Table; +import org.onap.aaf.auth.gui.Table.Cells; +import org.onap.aaf.auth.gui.table.AbsCell; +import org.onap.aaf.auth.gui.table.RefCell; +import org.onap.aaf.auth.gui.table.TableData; +import org.onap.aaf.auth.gui.table.TextCell; +import org.onap.aaf.cadi.CadiException; +import org.onap.aaf.cadi.client.Future; +import org.onap.aaf.cadi.client.Rcli; +import org.onap.aaf.cadi.client.Retryable; +import org.onap.aaf.misc.env.APIException; +import org.onap.aaf.misc.env.Env; +import org.onap.aaf.misc.env.TimeTaken; +import org.onap.aaf.misc.env.util.Chrono; + +import aaf.v2_0.UserRole; +import aaf.v2_0.UserRoles; + + +/** + * Page content for My Roles + * + * @author Jonathan + * + */ +public class RolesShow extends Page { + public static final String HREF = "/gui/myroles"; + private static final String DATE_TIME_FORMAT = "yyyy-MM-dd"; + private static SimpleDateFormat expiresDF; + + static { + expiresDF = new SimpleDateFormat(DATE_TIME_FORMAT); + } + + public RolesShow(final AAF_GUI gui, final Page ... breadcrumbs) throws APIException, IOException { + super(gui.env, "MyRoles",HREF, NO_FIELDS, + new BreadCrumbs(breadcrumbs), + new Table("Roles",gui.env.newTransNoAvg(),new Model(), "class=std")); + } + + /** + * Implement the Table Content for Permissions by User + * + * @author Jonathan + * + */ + private static class Model extends TableData { + private static final String[] headers = new String[] {"Role","Expires","Remediation","Actions"}; + + @Override + public String[] headers() { + return headers; + } + + @Override + public Cells get(final AuthzTrans trans, final AAF_GUI gui) { + Cells rv = Cells.EMPTY; + + try { + rv = gui.clientAsUser(trans.getUserPrincipal(), new Retryable() { + @Override + public Cells code(Rcli client) throws CadiException, ConnectException, APIException { + ArrayList rv = new ArrayList(); + TimeTaken tt = trans.start("AAF Roles by User",Env.REMOTE); + try { + Future fur = client.read("/authz/userRoles/user/"+trans.user(),gui.getDF(UserRoles.class)); + if (fur.get(5000)) { + if(fur.value != null) for (UserRole u : fur.value.getUserRole()) { + if(u.getExpires().compare(Chrono.timeStamp()) < 0) { + AbsCell[] sa = new AbsCell[] { + new TextCell(u.getRole() + "*", "class=expired"), + new TextCell(expiresDF.format(u.getExpires().toGregorianCalendar().getTime()),"class=expired"), + new RefCell("Extend", + UserRoleExtend.HREF + "?user="+trans.user()+"&role="+u.getRole(), + false, + new String[]{"class=expired"}), + new RefCell("Remove", + UserRoleRemove.HREF + "?user="+trans.user()+"&role="+u.getRole(), + false, + new String[]{"class=expired"}) + + }; + rv.add(sa); + } else { + AbsCell[] sa = new AbsCell[] { + new RefCell(u.getRole(), + RoleDetail.HREF+"?role="+u.getRole(), + false), + new TextCell(expiresDF.format(u.getExpires().toGregorianCalendar().getTime())), + AbsCell.Null, + new RefCell("Remove", + UserRoleRemove.HREF + "?user="+trans.user()+"&role="+u.getRole(), + false) + }; + rv.add(sa); + } + } + } + + } finally { + tt.done(); + } + return new Cells(rv,null); + } + }); + } catch (Exception e) { + trans.error().log(e); + } + return rv; + } + } +} diff --git a/auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/pages/UserRoleExtend.java b/auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/pages/UserRoleExtend.java new file mode 100644 index 00000000..c0ba16da --- /dev/null +++ b/auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/pages/UserRoleExtend.java @@ -0,0 +1,99 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.gui.pages; + +import java.io.IOException; +import java.net.ConnectException; + +import org.onap.aaf.auth.env.AuthzTrans; +import org.onap.aaf.auth.gui.AAF_GUI; +import org.onap.aaf.auth.gui.BreadCrumbs; +import org.onap.aaf.auth.gui.NamedCode; +import org.onap.aaf.auth.gui.Page; +import org.onap.aaf.cadi.CadiException; +import org.onap.aaf.cadi.client.Future; +import org.onap.aaf.cadi.client.Rcli; +import org.onap.aaf.cadi.client.Retryable; +import org.onap.aaf.misc.env.APIException; +import org.onap.aaf.misc.env.Env; +import org.onap.aaf.misc.env.Slot; +import org.onap.aaf.misc.env.TimeTaken; +import org.onap.aaf.misc.xgen.Cache; +import org.onap.aaf.misc.xgen.DynamicCode; +import org.onap.aaf.misc.xgen.html.HTMLGen; + +public class UserRoleExtend extends Page { + public static final String HREF = "/gui/urExtend"; + static final String NAME = "Extend User Role"; + static final String fields[] = {"user","role"}; + + public UserRoleExtend(final AAF_GUI gui, final Page ... breadcrumbs) throws APIException, IOException { + super(gui.env,NAME, HREF, fields, + new BreadCrumbs(breadcrumbs), + new NamedCode(true, "content") { + @Override + public void code(final Cache cache, final HTMLGen hgen) throws APIException, IOException { + final Slot sUser = gui.env.slot(NAME+".user"); + final Slot sRole = gui.env.slot(NAME+".role"); + + + cache.dynamic(hgen, new DynamicCode() { + @Override + public void code(final AAF_GUI gui, final AuthzTrans trans, final Cache cache, final HTMLGen hgen) throws APIException, IOException { + final String user = trans.get(sUser, ""); + final String role = trans.get(sRole, ""); + + TimeTaken tt = trans.start("Request to extend user role",Env.REMOTE); + try { + gui.clientAsUser(trans.getUserPrincipal(), new Retryable() { + @Override + public Void code(Rcli client)throws CadiException, ConnectException, APIException { + Future fv = client.setQueryParams("request=true").update("/authz/userRole/extend/"+user+"/"+role); + if(fv.get(5000)) { + // not sure if we'll ever hit this + hgen.p("Extended User ["+ user+"] in Role [" +role+"]"); + } else { + if (fv.code() == 202 ) { + hgen.p("User ["+ user+"] in Role [" +role+"] Extension sent for Approval"); + } else { + gui.writeError(trans, fv, hgen,0); + } + } + return null; + } + }); + } catch (Exception e) { + trans.error().log(e); + e.printStackTrace(); + } finally { + tt.done(); + } + + + } + }); + } + + }); + } +} + diff --git a/auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/pages/UserRoleRemove.java b/auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/pages/UserRoleRemove.java new file mode 100644 index 00000000..5f8adf2d --- /dev/null +++ b/auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/pages/UserRoleRemove.java @@ -0,0 +1,97 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.gui.pages; + +import java.io.IOException; +import java.net.ConnectException; + +import org.onap.aaf.auth.env.AuthzTrans; +import org.onap.aaf.auth.gui.AAF_GUI; +import org.onap.aaf.auth.gui.BreadCrumbs; +import org.onap.aaf.auth.gui.NamedCode; +import org.onap.aaf.auth.gui.Page; +import org.onap.aaf.cadi.CadiException; +import org.onap.aaf.cadi.client.Future; +import org.onap.aaf.cadi.client.Rcli; +import org.onap.aaf.cadi.client.Retryable; +import org.onap.aaf.misc.env.APIException; +import org.onap.aaf.misc.env.Env; +import org.onap.aaf.misc.env.Slot; +import org.onap.aaf.misc.env.TimeTaken; +import org.onap.aaf.misc.xgen.Cache; +import org.onap.aaf.misc.xgen.DynamicCode; +import org.onap.aaf.misc.xgen.html.HTMLGen; + +public class UserRoleRemove extends Page { + public static final String HREF = "/gui/urRemove"; + static final String NAME = "Remove User Role"; + static final String fields[] = {"user","role"}; + + public UserRoleRemove(final AAF_GUI gui, final Page ... breadcrumbs) throws APIException, IOException { + super(gui.env,NAME, HREF, fields, + new BreadCrumbs(breadcrumbs), + new NamedCode(true, "content") { + @Override + public void code(final Cache cache, final HTMLGen hgen) throws APIException, IOException { + final Slot sUser = gui.env.slot(NAME+".user"); + final Slot sRole = gui.env.slot(NAME+".role"); + + + cache.dynamic(hgen, new DynamicCode() { + @Override + public void code(final AAF_GUI gui, final AuthzTrans trans, final Cache cache, final HTMLGen hgen) throws APIException, IOException { + final String user = trans.get(sUser, ""); + final String role = trans.get(sRole, ""); + + TimeTaken tt = trans.start("Request a user role delete",Env.REMOTE); + try { + gui.clientAsUser(trans.getUserPrincipal(), new Retryable() { + @Override + public Void code(Rcli client) throws CadiException, ConnectException, APIException { + Future fv = client.setQueryParams("request=true").delete( + "/authz/userRole/"+user+"/"+role,Void.class); + + if(fv.get(5000)) { + // not sure if we'll ever hit this + hgen.p("User ["+ user+"] Removed from Role [" +role+"]"); + } else { + if (fv.code() == 202 ) { + hgen.p("User ["+ user+"] Removal from Role [" +role+"] sent for Approval"); + } else { + gui.writeError(trans, fv, hgen, 0); + } + } + return null; + } + }); + } catch (Exception e) { + e.printStackTrace(); + } finally { + tt.done(); + } + } + }); + } + + }); + } +} diff --git a/auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/pages/WebCommand.java b/auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/pages/WebCommand.java new file mode 100644 index 00000000..f9c57d0f --- /dev/null +++ b/auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/pages/WebCommand.java @@ -0,0 +1,118 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.gui.pages; + +import java.io.IOException; + +import org.onap.aaf.auth.env.AuthzTrans; +import org.onap.aaf.auth.gui.AAF_GUI; +import org.onap.aaf.auth.gui.BreadCrumbs; +import org.onap.aaf.auth.gui.NamedCode; +import org.onap.aaf.auth.gui.Page; +import org.onap.aaf.misc.env.APIException; +import org.onap.aaf.misc.xgen.Cache; +import org.onap.aaf.misc.xgen.DynamicCode; +import org.onap.aaf.misc.xgen.Mark; +import org.onap.aaf.misc.xgen.html.HTMLGen; + +public class WebCommand extends Page { + public static final String HREF = "/gui/cui"; + + public WebCommand(final AAF_GUI gui, final Page ... breadcrumbs) throws APIException, IOException { + super(gui.env, "Web Command Client",HREF, NO_FIELDS, + new BreadCrumbs(breadcrumbs), + new NamedCode(true, "content") { + @Override + public void code(final Cache cache, final HTMLGen hgen) throws APIException, IOException { + hgen.leaf("p","id=help_msg") + .text("Questions about this page? ") + .leaf("a", "href="+gui.env.getProperty(AAF_URL_CUIGUI,""), "target=_blank") + .text("Click here") + .end() + .text(". Type 'help' below for a list of AAF commands") + .end() + + .divID("console_and_options"); + hgen.divID("console_area"); + hgen.end(); //console_area + + hgen.divID("options_link", "class=closed"); + hgen.img("src=../../"+gui.theme + "/options_down.png", "onclick=handleDivHiding('options',this);", + "id=options_img", "alt=Options", "title=Options") + .end(); //options_link + + hgen.divID("options"); + cache.dynamic(hgen, new DynamicCode() { + @Override + public void code(AAF_GUI state, AuthzTrans trans, Cache cache, HTMLGen xgen) + throws APIException, IOException { + switch(browser(trans,trans.env().slot(getBrowserType()))) { + case ie: + case ieOld: + // IE doesn't support file save + break; + default: + xgen.img("src=../../"+gui.theme+"/AAFdownload.png", "onclick=saveToFile();", + "alt=Save log to file", "title=Save log to file"); + } +// xgen.img("src=../../"+gui.theme+"/AAFemail.png", "onclick=emailLog();", +// "alt=Email log to me", "title=Email log to me"); + xgen.img("src=../../"+gui.theme+"/AAF_font_size.png", "onclick=handleDivHiding('text_slider',this);", + "id=fontsize_img", "alt=Change text size", "title=Change text size"); + xgen.img("src=../../"+gui.theme+"/AAF_details.png", "onclick=selectOption(this,0);", + "id=details_img", "alt=Turn on/off details mode", "title=Turn on/off details mode"); + xgen.img("src=../../"+gui.theme+"/AAF_maximize.png", "onclick=maximizeConsole(this);", + "id=maximize_img", "alt=Maximize Console Window", "title=Maximize Console Window"); + } + }); + hgen.divID("text_slider"); + hgen.tagOnly("input", "type=button", "class=change_font", "onclick=buttonChangeFontSize('dec')", "value=-") + .tagOnly("input", "id=text_size_slider", "type=range", "min=75", "max=200", "value=100", + "oninput=changeFontSize(this.value)", "onchange=changeFontSize(this.value)", "title=Change Text Size") + .tagOnly("input", "type=button", "class=change_font", "onclick=buttonChangeFontSize('inc')", "value=+") + .end(); //text_slider + + hgen.end(); //options + hgen.end(); //console_and_options + + hgen.divID("input_area"); + hgen.tagOnly("input", "type=text", "id=command_field", + "autocomplete=off", "autocorrect=off", "autocapitalize=off", "spellcheck=false", + "onkeypress=keyPressed()", "placeholder=Type your AAFCLI commands here", "autofocus") + .tagOnly("input", "id=submit", "type=button", "value=Submit", + "onclick=http('put','../../gui/cui',getCommand(),callCUI);") + .end(); + + Mark callCUI = new Mark(); + hgen.js(callCUI); + hgen.text("function callCUI(resp) {") + .text("moveCommandToDiv();") + .text("printResponse(resp);") + .text("}"); + hgen.end(callCUI); + + } + }); + + } + +} diff --git a/auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/table/AbsCell.java b/auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/table/AbsCell.java new file mode 100644 index 00000000..6d95d7d8 --- /dev/null +++ b/auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/table/AbsCell.java @@ -0,0 +1,48 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.gui.table; + +import org.onap.aaf.misc.xgen.html.HTMLGen; + +public abstract class AbsCell { + public static final AbsCell[] HLINE = new AbsCell[0]; + private static final String[] NONE = new String[0]; + protected static final String[] CENTER = new String[]{"class=center"}; + protected static final String[] LEFT = new String[]{"class=left"}; + protected static final String[] RIGHT = new String[]{"class=right"}; + + /** + * Write Cell Data with HTMLGen generator + * @param hgen + */ + public abstract void write(HTMLGen hgen); + + public final static AbsCell Null = new AbsCell() { + @Override + public void write(final HTMLGen hgen) { + } + }; + + public String[] attrs() { + return NONE; + } +} diff --git a/auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/table/ButtonCell.java b/auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/table/ButtonCell.java new file mode 100644 index 00000000..986c90af --- /dev/null +++ b/auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/table/ButtonCell.java @@ -0,0 +1,45 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.gui.table; + +import org.onap.aaf.misc.xgen.html.HTMLGen; + +public class ButtonCell extends AbsCell { + private String[] attrs; + + public ButtonCell(String value, String ... attributes) { + attrs = new String[2+attributes.length]; + attrs[0]="type=button"; + attrs[1]="value="+value; + System.arraycopy(attributes, 0, attrs, 2, attributes.length); + } + @Override + public void write(HTMLGen hgen) { + hgen.incr("input",true,attrs).end(); + + } + + @Override + public String[] attrs() { + return AbsCell.CENTER; + } +} diff --git a/auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/table/CheckBoxCell.java b/auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/table/CheckBoxCell.java new file mode 100644 index 00000000..4c723d4a --- /dev/null +++ b/auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/table/CheckBoxCell.java @@ -0,0 +1,66 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.gui.table; + +import org.onap.aaf.misc.xgen.html.HTMLGen; + +public class CheckBoxCell extends AbsCell { + public enum ALIGN{ left, right, center }; + private String[] attrs; + private ALIGN align; + + public CheckBoxCell(String name, ALIGN align, String value, String ... attributes) { + this.align = align; + attrs = new String[3 + attributes.length]; + attrs[0]="type=checkbox"; + attrs[1]="name="+name; + attrs[2]="value="+value; + System.arraycopy(attributes, 0, attrs, 3, attributes.length); + } + + public CheckBoxCell(String name, String value, String ... attributes) { + this.align = ALIGN.center; + attrs = new String[3 + attributes.length]; + attrs[0]="type=checkbox"; + attrs[1]="name="+name; + attrs[2]="value="+value; + System.arraycopy(attributes, 0, attrs, 3, attributes.length); + } + + @Override + public void write(HTMLGen hgen) { + hgen.tagOnly("input",attrs); + } + + @Override + public String[] attrs() { + switch(align) { + case left: + return AbsCell.LEFT; + case right: + return AbsCell.RIGHT; + case center: + default: + return AbsCell.CENTER; + } + } +} diff --git a/auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/table/RadioCell.java b/auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/table/RadioCell.java new file mode 100644 index 00000000..9f092105 --- /dev/null +++ b/auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/table/RadioCell.java @@ -0,0 +1,48 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.gui.table; + +import org.onap.aaf.misc.xgen.html.HTMLGen; + +public class RadioCell extends AbsCell { + private String[] attrs; + + public RadioCell(String name, String radioClass, String value, String ... attributes) { + attrs = new String[4 + attributes.length]; + attrs[0]="type=radio"; + attrs[1]="name="+name; + attrs[2]="class="+radioClass; + attrs[3]="value="+value; + System.arraycopy(attributes, 0, attrs, 4, attributes.length); + + } + + @Override + public void write(HTMLGen hgen) { + hgen.tagOnly("input",attrs); + } + + @Override + public String[] attrs() { + return AbsCell.CENTER; + } +} diff --git a/auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/table/RefCell.java b/auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/table/RefCell.java new file mode 100644 index 00000000..7dc14c81 --- /dev/null +++ b/auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/table/RefCell.java @@ -0,0 +1,54 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.gui.table; + +import static org.onap.aaf.misc.xgen.html.HTMLGen.A; + +import org.onap.aaf.misc.xgen.html.HTMLGen; + +/** + * Write a Reference Link into a Cell + * @author Jonathan + * + */ +public class RefCell extends AbsCell { + public final String name; + public final String[] str; + + public RefCell(String name, String href, boolean newWindow, String... attributes) { + this.name = name; + if(newWindow) { + str = new String[attributes.length+2]; + str[attributes.length]="target=_blank"; + } else { + str = new String[attributes.length+1]; + } + str[0]="href="+href; + System.arraycopy(attributes, 0, str, 1, attributes.length); + + } + + @Override + public void write(HTMLGen hgen) { + hgen.leaf(A,str).text(name); + } +} diff --git a/auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/table/TableData.java b/auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/table/TableData.java new file mode 100644 index 00000000..731d425e --- /dev/null +++ b/auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/table/TableData.java @@ -0,0 +1,56 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.gui.table; + +import org.onap.aaf.auth.gui.Table; +import org.onap.aaf.misc.env.Env; +import org.onap.aaf.misc.env.Trans; +import org.onap.aaf.misc.xgen.Cache; +import org.onap.aaf.misc.xgen.html.HTMLGen; +import org.onap.aaf.misc.xgen.html.State; + +public abstract class TableData, TRANS extends Trans> implements Table.Data{ + public static final String[] headers = new String[0]; + + /* (non-Javadoc) + * @see org.onap.aaf.auth.gui.Table.Data#prefix(org.onap.aaf.misc.xgen.html.State, com.att.inno.env.Trans, org.onap.aaf.misc.xgen.Cache, org.onap.aaf.misc.xgen.html.HTMLGen) + */ + @Override + public void prefix(final S state, final TRANS trans, final Cache cache, final HTMLGen hgen) { + } + + /* (non-Javadoc) + * @see org.onap.aaf.auth.gui.Table.Data#postfix(org.onap.aaf.misc.xgen.html.State, com.att.inno.env.Trans, org.onap.aaf.misc.xgen.Cache, org.onap.aaf.misc.xgen.html.HTMLGen) + */ + @Override + public void postfix(final S state, final TRANS trans, final Cache cache, final HTMLGen hgen) { + } + + /* (non-Javadoc) + * @see org.onap.aaf.auth.gui.Table.Data#headers() + */ + @Override + public String[] headers() { + return headers; + } + +} diff --git a/auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/table/TextAndRefCell.java b/auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/table/TextAndRefCell.java new file mode 100644 index 00000000..036c8b7f --- /dev/null +++ b/auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/table/TextAndRefCell.java @@ -0,0 +1,43 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.gui.table; + +import static org.onap.aaf.misc.xgen.html.HTMLGen.A; + +import org.onap.aaf.misc.xgen.html.HTMLGen; + +public class TextAndRefCell extends RefCell { + + private String text; + + public TextAndRefCell(String text, String name, String href, boolean newWindow, String[] attributes) { + super(name, href, newWindow, attributes); + this.text = text; + } + + @Override + public void write(HTMLGen hgen) { + hgen.text(text); + hgen.leaf(A,str).text(name); + } + +} diff --git a/auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/table/TextCell.java b/auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/table/TextCell.java new file mode 100644 index 00000000..e20367a7 --- /dev/null +++ b/auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/table/TextCell.java @@ -0,0 +1,49 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.gui.table; + +import org.onap.aaf.misc.xgen.html.HTMLGen; + +/** + * Write Simple Text into a Cell + * @author Jonathan + * + */ +public class TextCell extends AbsCell { + public final String name; + private String[] attrs; + + public TextCell(String name, String... attributes) { + attrs = attributes; + this.name = name; + } + + @Override + public void write(HTMLGen hgen) { + hgen.text(name); + } + + @Override + public String[] attrs() { + return attrs; + } +} diff --git a/auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/table/TextInputCell.java b/auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/table/TextInputCell.java new file mode 100644 index 00000000..4a4f757c --- /dev/null +++ b/auth/auth-gui/src/main/java/org/onap/aaf/auth/gui/table/TextInputCell.java @@ -0,0 +1,54 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.gui.table; + +import org.onap.aaf.misc.xgen.html.HTMLGen; + +/** + * Create an Input Cell for Text + * @author Jonathan + * + */ +public class TextInputCell extends AbsCell { + private static final String[] NULL_ATTRS=new String[0]; + private String[] attrs; + + public TextInputCell(String name, String textClass, String value, String ... attributes) { + attrs = new String[5 + attributes.length]; + attrs[0]="type=text"; + attrs[1]="name="+name; + attrs[2]="class="+textClass; + attrs[3]="value="+value; + attrs[4]="style=font-size:100%;"; + System.arraycopy(attributes, 0, attrs, 5, attributes.length); + } + + @Override + public void write(HTMLGen hgen) { + hgen.tagOnly("input",attrs); + } + + @Override + public String[] attrs() { + return NULL_ATTRS; + } +} diff --git a/auth/auth-gui/theme/onap/AAF_details.png b/auth/auth-gui/theme/onap/AAF_details.png new file mode 100644 index 0000000000000000000000000000000000000000..5c187459255b22df00373dda3f2b8ae0b2059575 GIT binary patch literal 650 zcmV;50(Jd~P)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGmbN~PnbOGLGA9w%&0v}04K~zXf<(Azm z!%-N=CodP0T!@lf;Kq%6S4#Na!PokWb#e?M?0 z8UGK^e{7`^wR%xM`baDBMPtyHD3VA3V=ctsGiF2jhyf7y>qk%J)B%**tie<1E!wJ? zL+H-=5{|(I5cdn4GqY_WyIlwMZd}Zs+;puOF#_dw=&VnkkPMN4l98R9cAe?L1(E!C zeSWM7%4pS=jT@o@cwT++b*la?lf~hNm;%U`&XODF{x-nw_9BzhN7qd3RBIi^M# z)e7)%mVB{daz7}bbaXGjdnH;x`NTfL?AbVnkPx#1ZP1_K>z@;j|==^1poj532;bRa{vGmbN~PnbOGLGA9w%&1eHldK~z{r-B(>q z990zlc6N8@!U_nKp9K_!B4|rODG$~*txaiDkyI;b)x`KvQxl)8Hq}-P^{1L>qA{jE z_+sS6#8ew2rqncTjWPOw6$3^aTjL)Tq=_x%Z)ay`{mz};%L2>NNV6s$GVGn1bMHC# zJKs6?j3-7Zefb1N$1V801~MUb)WPzgiQ$f|@RYpN6B`)|!}NPIVO!g#CO{Kj2pm{4hMG9eH?lIif5$>14?cVA{r$ z>u%LH9%Aeh^8BV+z;U2ZT0oZMfH2*g(Y|oEiEO6jBf8+AX);fTCJo8dwkP-oFDuRvGMc7zVLNO^cA@9FhN14DYseT@~c7a-$&1g31fx~*PM-n*Uzv!e4MB>DDl zm`T0PljnelgUAGPpAL7N;C)=)Y`YzpjHC>~tV$@PlFAi6+=`?9Lx>XkT@B^%Jar7d zEI*8RRTDiw$J5kP@DktdpN3(0JV?~NN$$9PRY)5xJN!9@ud?r$bNbFgz~Q8AwZ&@E zk*|M6SMQ%{+}?E4EC@yK-g;M0gm%$ZU#hC$J@G5qxahpNtCEl4&%R>1Z`bYp^YCuHv)$ZNGjvXIpG9D_+Ibt+JSd> zG{6bZ98d}Y@w6b@k4hGmfsrxcqE0z^7w{XXWlbMtj!!XEq1|Bh?=lMT4nCN={3q?!-0000Px#1ZP1_K>z@;j|==^1poj532;bRa{vGmbN~PnbOGLGA9w%&0p>|WK~z{r#h1HI z!!Q(vkJH;i*h;I;6+27Es7O>Gb>IQIbtghXER+p8m4Vk_r&4(hB;J9`1}wb>pWJZV zIJPS{JyRl``2WuD6DNmwH0t*+@bx=`V!?tuVzFF7b*~KXx2HgAcN6d9dkW=JArI|X zV>VwxZNCE6C#^hhail;^)V4~gwiC_`{@#pPs4duZk5h>5*Fjnx2i`jN#zdN3$AdLs z(6*u3K7@XVK#-A7%fM3r5U$}x zF{3gVCo-`iu_w|(p$QdLGt!7a93R;tfDNO|E=-3GJk-Q=TLg$iZE)QHWK>@V$pL@? zxu77uMuH-<3HfG9Gcv7tgXeGy9B`|_Qk3qvVa?i|$a100000NkvXXu0mjfZv*?B literal 0 HcmV?d00001 diff --git a/auth/auth-gui/theme/onap/AAFdownload.png b/auth/auth-gui/theme/onap/AAFdownload.png new file mode 100644 index 0000000000000000000000000000000000000000..cebd95223478bf7168c05b5b2162d926ae31d98e GIT binary patch literal 1834 zcmV+_2i5qAP)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGmbN~PnbOGLGA9w%&2ER!}K~z{rwO4D1 zRaF%J_IcgMTpgX!e9f4Taq?A>rYWhQR7Cp2#0VsbAR>B685mLIk6uP3YCn2F)DNj2 zfuKeBt1u`S1yg!6=37V8nYlUldCoq&Z|!p@9i6MFxi9;kbI;j(t+m(s*0 zK792{6{k-W5yFAO|2>QqDBqr|(AMf>`Rp7f4@*PsIax5Te%^(S?+ehef#dw&%0=G! zBSl&xm-et^X%-t+v_h@ldCYA3=q$26?Q>mw{>0uJGsKj#4w1(GmJWl**!>ndKGLP(m`xF^WZs^fcE9l&)-q=R4355w~*V z5wrj2B78qd6R5$HkkLUkGMLkr#>0ym(Z_qo)Ycjo4LOb1KRttdq(NVz|J8+1mep1V zzbZWV>ZK#0R=j)C{N9I;-x0Lg-ZQ!FM+F%gN5WPVNUz$qbE%9(zSINiqY;sWU((R$Q%@#SOq5(a zT_(DY9mK})THgS^<{D-I*UFv&a^$ytCVF^fD6IEmEivOmKgr#M#l%v^lZ(aWxr~c> zZCT75pFwL=V!*(BNq)^3m&T0oDa@IYvN0ATtUU3Y;KKs622_fX1W*fKJYrIf0b+vD zScFHmda+7V3F|`aqR(i2@^mAnjmagdW3J^=B^20iO{{G(ld=7W65jaw6ozssGSQ1LH zPG>nAhWNl=Bf)1urq# zGeV^lq3@hVp%9V6`MVk-)Gk&o9!&$DJ!p=1hqYLY{o<&p2AY>G^xW4KkGG&G#pugyDk!RVKl`u3|zGzeu zmRew}Adeq8S+S^)r^UT_7N9Vs)egc61v6_FuI)s}p9PBn*|T}uX*{!~3qGnSmmHg3 zVHxNtRM1y&D2pT}*kS18Q`2bg>48J^K(9ru#IQ;*j>tK9@5u=$R;z5E(pdfW9~Q+- z9-b_Osk-Q{g!pOmG;|y|hsWPJj+>fgzY@67y)kCC=J4_(BT*_CdH`6x;Q)r_SjKCi zE3+0nxQHQ`%@7+>9XWite!_n;)O~v~wpsijIpCsP)eHe!GSPZI=ZR7Zy|^o!IW~=U=6735 z8k1TwXdjnF`^_0lY4I>)at`f$KBYB-$$U4tC5v0e11;7gG9)`h2b&pUK&Ehk?Vuzo zchUo=y9<_LB`rcy^O)f-cE2wk&`cR_w!k4au5xICRN7pLeXwjV#?iCl0XcQK3Oq2M z5NjQ-aEF z041XP*3mhrdtW+iA{HBAv{?H@tyDu9S8gn?J}`28s~){Y4|h-CpVO`1^_evvpTw-` z85SPaXO`a^IRs(76@_1ai?Qp?W+AZ9e6zcZFLo7CWeP}3bt4CB8JaU5o>-Q`?UQo& Y7c^3lExr!}S^xk507*qoM6N<$g5c0h;s5{u literal 0 HcmV?d00001 diff --git a/auth/auth-gui/theme/onap/AAFemail.png b/auth/auth-gui/theme/onap/AAFemail.png new file mode 100644 index 0000000000000000000000000000000000000000..6d48776998fe16cdbbfdaade33e9be89b8663901 GIT binary patch literal 2277 zcmVv00001b5ch_0Itp) z=>Px#1ZP1_K>z@;j|==^1poj532;bRa{vGmbN~PnbOGLGA9w%&2zp6GK~z{rtypc0 zTvZu<&dkp4%r&)$!@ z_uS_^@B2RQdyeyLy@PjRyfh7D+5out&pCKr>6{mcFT%CXQ|!sT@Y8|^jS+=+^^o4v zJv-+G|8(gi{SaTHRzsmXi{j4?!1ccW4qq(I0G(O5G(ond;8H|j-4KRj7~Jl?!RCqB z8!UnssJQzE??(-w!RvYreyW1Lo*WTuKIGArhwEsE%cR-c;8Q%drDLFCF#)FYgv}-u z%K$7e36qH#3|K@KdDMBm4qqqGYR$T*g`L}ayGLgZ$Yqgg&%hI8N@hS8B4&5MS;_?(J*kHz?^{2RN*V^d06y`#g< z!E-yd^m- zKGo9+m(OxQ0pY{^sN;hI?PzNAQL$*&ZZ$bAQf;8n*^Uovd=vIoxgqw zPyY2RUOqR8_8dX92AMG#Gb%rHX66PW28)x4)u(3=vAfb#01F1qPM|b##PM8}CN_}Mh{{z1 zNd&Q9*sLt-)I)q2d!f&PQRnR2IhnZt|8jP6){~EYY!lXATtHR9(At_-Nh~CClfV+D z_&QcQIjcaLP)JV#EF);mt$8z!ZN^+V^)|1_v4Enx!U~m2hX2r{4S&7`OkE5-F@+S8&3y}m8VY*0P zWCS9j>^Mmedo;xiSRBPQyY|D~blm&e$SM5v8}|S!R={;L(j^g+3(0~aUAk#N>B7uP z9DW|iXHJb_c&f^Tbv`3mc4MTcd2jo-evgbMtf-brldNI@712Q#rHu?0jEvwtd-fu; zat++zcf4QSPa?a4`@eh?(<7t6%8QWh>V#)tq@-s8O8xR}8Kej{A{%x2*s=3W-tns! zap2p3018YD!bxe8Ip6X2OK|dqv&c{d%;01(B706Im0Jm15bmf<_J&81BU!iXzZD}T z;MHOBvTo;Xw@JpNq1$(C#=x4j`17+TY-UzuG_wTtQXHxnkj3aj6=Hes`c-D~Etjpp zws)?^Q~xOksbv zIBx#v4JZ}?CL5GlRv450^y@<2+!0+}B!KVV{`n)8s@%%Hm`!B{3cayPvqkjL2H6}x zx&uABzewBiwWsj(-^nJ;-efQ2=7=c#$e7X|4u0iJv=lH-ysRxSE@CI*f@@Zr;g5VC zM~)rDyS8nC|JP|WCZ?D}r)}1#Xy#;@*#Ts~K*{;dKWUQ%+I_!$2~R)&3euF7*sOei zn#>VJW4r|a@+n+(?PeUlj{x~yeSdD7$E0E;1TpfRz_~Le96NH%rsMj0;c^VBX0FX3 z;>gi70h7(W*T2mQ8A))KL3Y;@e=;9TXZSKpFGf)eR3M9_h}U}$?Zd#uU6^95sMe6? zSNLcvlM8}OW}{r6rz_ll?{WP5#7STvNL4Vua=aqnz}A!|LgN=x)JAEabXTbkGc`o? zKSjfuD>vd(dv~E+HWjiae}7#d^|Asb%b-2+%nNw*!AF4Z98y85Or}hlXnXldQn4#z zktt(PfnwT6M5E*Q&?k1|%1u{bhCbJtgmkV~IF}1BSpZlFK{Y^P?hCn?iX^GX(80S= zo}jrTRb

    7*wq26F+hMnlgz|B!Ke6(IWEQ-8eAxSsR*3ZeD8zSt8*RA#h@I3nWdN zCy2#BCaf|!;m1!rho2vR%x0JB=ZrpJ-Mn`6|*NSvO zknbbNfn|V92F(%IE6mpqe*Gboi(_y-%m!9}vUs*in*hgHOBTAZ=aaYK(lveNe~Yzw zAo=_-$S$`RZ?%jv} zf&UG#`MnE(aAMNTtz{0)%}i)Zo8`3b9^fA@4&%v3e~414#30LKaOVx!u<;U1(sh^G zWB?^31aKe=c?4xuM6bdcbj92MU5!a2X@6KH%9Q2-N1hVbXU`AAlV`O00000NkvXXu0mjf0s392 literal 0 HcmV?d00001 diff --git a/auth/auth-gui/theme/onap/LF_Collab_footer_gray.png b/auth/auth-gui/theme/onap/LF_Collab_footer_gray.png new file mode 100644 index 0000000000000000000000000000000000000000..abbf4b1a0910e1465995f2ec4689a5ad8aafc8e8 GIT binary patch literal 47307 zcmbTdc_376_&?mPMLd!`$nr?E*=CaLiHK}jlO_ox$!;8srScR)l9I7z9R?#wn6V_X zj(x_6nX!y@hBF8w>+kg4-uI91`}^bd2Q$aHmvi6OeO;gH^SMrpg_+^;qoPOm?AdeN z=%&8qo;?R?&}WOo`=Q^LvkjpOdqe_m+zGJqMg{;*ey)3TUA!Ndv$v;$)1P}3f;@eo)_eA7>IC^XIeWMUNIi6QbNAAc<`5gC zrQBV#r0rBpl}vr~TpzjL4DoZd3Nf>G4)JhSbCK53meLGThdS_d4RDeQ@_gduuO6f& z{U80RL!bX#R+N_dk6Qvfw50!YQg=)(r1ZS~T%}YLl;oY2t|&=eQC3ifUshFBy(9%w zQdUw_f+;G)KpvmSkN~u=|=$pKI)2!001Zea0PEa zH$`PNHMKu|z+m#w9rFIcUI9))@?QRD{<{Z#SASo*me}JXy|1*vM^=^ObU>{dSOILqy zl%F%SAILNR-56TC|NB6HZiHr|Ztmv}ZHm(qeQ#%!r>j?hk-nBR^dAKmcNg`mx~i&h zy{jt9S7Az5t|}{E)lTvxdQSH7aEtn@!^jlBE=oV=V}|9f0_Xx#s5d*%PyR$b4})hWQ+&)VDj$$wjb z#Ut+kZ~sT$K2myCDpICS&hB1+zW>>t|9o0~S3mbaR~G|6Z%?WJSYLJb|7HBE2D+D3 zpb5kNKcD+Q+q(S!Su;gwGKznU0FnX>BX7s2ms|*AVIo zaV0}PhpE(|AFXXYJ-vv2?usu}ZSCz<)r9^5%BN4Czf@MePI%k! z?fdJ*r1tiXy84Ec)C^)>J=ELxrsk#}Ej7eiVr@fbC#kHw;#*@QsjH``xU{6Kyti+F z#bV9P&CSlv&dkiP+3e}*=~))5r?+orZf<5~c7RNoo}HbWW0AVL$Hymn`}(`Od#0wQ z8H~}s{(-UaaV)Nw#bS?+j*X3tQwFIMlarIv)19QQi3uijZE|vo&R{U7rs&Y0(NP+W z&KMo*>hAqHJks6M%VbWrwso|3kV-#&9vvMWXEMhoCKwDxQ3-y8M$67E$S=e}Epqb< zJ32{oY&MNfADdwI^^-?NXrp7}gM-wp?7Ym6xf7F9>6zJ`r0$HYoSxqP?jC4{Q+e1T z>d^4;@W|Ns1a;`=2#qn$oXp9`mREeG)9D{`@<(X&_Kwbv*?G{Ev$AsssXv)h(-RXD zBO@baaFqzD}{KD?; z9yWWPOrerUU2Sb0we{b+`}#?w?%Mi>j*iZro<16lMkWvDD2{x$>_|l7n`^2XB*cvx#3NP#G0>R);F@CSb#;9_UkC|4cRkocXQO6R|uzMQ=c_ z&0|QJHEWd-T-2z!S*_2}LJ6>tV-h|qj2lZ4ag12SPp)U! zrq$cYX^S>j77!;n!JU4g`!%RznPL`AnfupgP3^||9>!PER&*9q8a5;|)=^yT-gv5q zY+Q5C-EM-HVMOgrsyKap`*g~PBxhqcly{YpfMOb|YSARwFQYb@Zk{Q^-u!8@@-eH~ zM(c8(cXUpc-IkvZJ&{%EW?cIfreSQwPmf!!pc`bBne_>$z z{6(M6`CAk6b>+7v>|%tdM8(%xsG0dr=4wU-6IK0d=*POqPN+w1M9GrBop`V&!;O*{ zBz~pqXB@h_R$!NfQJomQ>X}yF!q#xp`bLn~{;mgKYu$W;dFF71G?b9lv~^@@&9uCw z6*D9(`78UN-Gtlcv5ufl$IQR=8k`J8r&vcEalSeJ0}{dG|mk6 z+OJ!0(ZH=+OeQexC|af==on9>$2c$LMiySFesC#V;ql=!Sk36sVk?Qb1fAvXpXF<< zqStrTDwqq~Js$(JrsW;4K2Nx>#6!h-hZ%;RE}O{`$jaP-cSoBCbK~F>iu$#K@=Hbw z5nLiu9zpKaVVB%#DiK_|1!wAOPQlIQTRI$`j323X9Y3=4fi&I9zGMEn;f~XU8*@}Y zh*`JZ8N{q8;rvh>5L288Y2;aYgu`x)uAhDI0~KmA=+o`C7>nvYwqAL4=0!0xEVG8q zT2I;awX5aZ_1#7eb~3k}b}2kt@bZb%_+x?Ny?I;&slay0z*xqrZ+@98i`YYSN*ZXc^ znf|Q>t?1#Qm9Qm&+Dx&C8}oWI6Yc1=FK+fr0op;sktN=*tJYUHv*Nj-i`z>^mD^bD zzZqn;x#bgUL7stJ_Xc5|jdPEKR=%7mXNY@5uihC$)$abw-OVZoAK~a- z8_7D~gy(0j?X<7QjWenq zYPm00O=NroTSPyydu1Ng-asW#i@_J+#RjN^gvG;b@9-B1jL*W3egpSIdBn68;`#0A zs@Lh+OH2Dzw;f|A481q>x6bf(O8y;}B}T~*ZIB5cy-m-~(D=B)GaXpOUKgaVC~wtx z1s$PUaQC1Rs-C1q>9l3=EZK_Bzw%Z_yB z64Gu{i@;M91fl-O>i4Ooi};%3yPpcdC4s?s#7nzuI?sfbqV91EZej0jD$|^oB~e!P z&D>j6D1*RAYLRTp+PF}(nOM4Bl=Iq(yKWD!vZR(p=2$Uv@wb@yAQ@!`)QXZug*g>Y zJ14hjvI;FT*QuUzml-?D?;Kmogiu=HGZDYL7y40;ewQ4}p1Mt!4=4obFU)llvcZx= zh^T(^P!&cLOCtHwkhph(5Z`l_c7Gx921*sDv9dXbsGf2!3|GaWL*G|F;FI|E{7j*D z7>`#l+adcWd0Bx{m%oB2Lf1~k1A17ujDuo(s zHr$r%EjEHWW0yE*a2oeP=X?TJ4#98F%%06^%+2`qUE0abQG`|pM(A)_ z*Ly~$mXP`6zgAhUF9^BUsrgGm&+}IxBN)VXDFld{Um(-VvS+77B~jvvpe2{M`{1?R zF>4@}#h|7P8uVVgQ4(6B^6K93Y>P8d^R6@b*wiJ*tHv+7`8|GLoZ)%ou$(;3-vu~R zKC~$w8m#rR3D-I4SRXWFS^vp~qxum9>G1?mbX4bO9lF-FnukXcp+QEh3Y=3WYu(|T zqN0)rQHyN`)xYG8=;LGK!%ecbK|m70fl1HJaeT&M6`1q3IE1er+4B8PG<3~)>Mg)h z;7GiGk2+I}9=eViz0NVCN{DZrAOzCfB5OAr^VmL%wVBTeGe$%5A>2YRl$77QS_oQz zX-vsax9P_j2$n>~#&{-KyzEL(4Zd}Rim2uro$>S-n@<8%gMh;IXLt60Ib9ZS8E_v> zKQ50YICx))qh$~k3h;(J-VWhr`3VFGm2k6wMQiRIH?J4hdzu$40H`gnV8NXot}>#V zviLZRsF{a5PMX4kS;z3;B3S*Jp=Ckce>$`_0vI&5nPr!_R%e#;z9RZyh=J7gLiXY; z;_7-Y3Khk$Vm7rs=docnD5JUSR~Nyh4GdzvG?!q=kSlxpFP^ts+ z_jecR7PIapeMFv`Kw`0j=SNG)4Oi*2)Y*>?L$?~DI zU*_pWOO1u>!K*=YAy4riR2VZ}=hYEt^7=YL%NUXHUNixFDqP%a=kJr^47%(!da3VX zFS>BY;UoBuhvt3B9XH2+Qtc-$9rJ$X{8>bC{l-#x|5xD?_UD4!E7+Usow}aIVlSOv z3`SXmDK+dpEFbsIao>dr@>t$-hVk$H=NKAy3U__|79s-{5kX14XS3#_YE+alcbHL8 zjDI(I`x@Oi5@U4XK4R1)-LunlefAVgq>yND4TM03@KU83yH3j7U+4n+x}<(}xsYu{ z_w-%?AN6cg2r#1LtcBPdzgGnMEy%#9T?|+ZEpwJc9kG#^L>gN=g;7ovIj1hZRooaB z`ga^2A*zVr_gO5zPLK2m<({t9u~XM7a`9G7qS=EIv~~vJa%O13 zCa)L&%rnv*Yv9pud%7jv$bIY7nWXGU&fA_bZO9n=|9-UP=6mei@eA&x*jtms_DhHR z{bmWZXurjo&{f>JmOhn_r{^d%#(wHfRKSAYqIbQ7`LBu1j|0FPQZF$rAcHRxuhm=W zP<;jsyb&qffxX4JO2MBo#Q8EA8QMFK{1*2zw8Br-5)X1g$ZKx!WG{J(B@tRTt?2v7 zT6AfS0%{acXBYLfw9;nycJ`NphA#+K%%$)0ursoH9FVnhP6)vY=eqAoaL&k{iI4Iy zuc957Z91AC#cIe`yyfInq}SMdk&iJ;5F+Qjz?J@cDSkw8kNG)W(*ov{*h@>d(jbr9 zLu+q0FT2#`uqxFQch0J~;Tk^L@ZVWG_K{r_D2RFXAvLZiA8&|~!-)I{dwEALslAsN zB~eXmuhe7iZ;yLMYEIaBX&lkHeB&QVhGZ0VbkSF{yN;)ASdw#%S>~MYu}hIVlwHIR zc?ur)Q0qZ)^0N4P11PXB9TnjKP% z7fyNxeDL7OdiF|>UV01GWDN459QVjKj6KH}Yh1wh=t%PIgvx={QzDN-Q;bkq2GG8F zodvQEqU4g4`+;LI)l9-TyPgkn?TO zaj$JBHW)ymRF5k6Y^e6Qk0&qXn@bMMs?Uh#E8gZZvD!E=%3GmD#jMxH?a~ese z`{B1dmnTbKyN{2{lNI;wJgvdptxGwXBlel;y;UhR%JlVZuqnHiy&hQl)bNII_P^_q z^Ef^Qqh>Al+BV*3;)^@S8RE@aIHD0f@>$OTAAk_(u8F4;lX|wMWvhRi_M*r%n|M+F zov=L-4|-9@R1r}+@+Sbuq<}<>z#~ucdSSE-=wPwXU9&!L(3b~j)l${u&8;*FMV_E* z)@GDu3x8xCr@E=%y&`b4KVkmfh^~%`=C9 z))5lr{~R#xN=5~mBj{yqp~&}W?k!_j6aK=^ST2Ey-S|~nGXF{9=LKy&Sfodx#vJjU zhW3Y*?SK3LC=74j!)<<85=>c|%46pPau{Vfc%6I0zd43fiS3Qx9OVa#8FzF?Ge~1x zmvO6P6k;U#%aqaN2LlB$zqt9$l^0jdpe#0P(yjS`nZgFy+7TDjk1wYeoXdN8Q4&vqsI|IJOFLFgyY4w;T{=`J+Gu93P3~w!oG^t8W_^_{FoSY zNcid+5aHsAOMR6|{nt2I(nYTN73N1eje`;a#!Trc|i@KlSik{oP0=I zT*LW3aGgARQt|HK6*fwyaJ}^%$F83}B6UDO$cvZYg$MO^3-A|eHmlm`OF??xN7dxv zBB3qsFna-hv(caC@uCSHF35dwc;O^Ci+g$8!=P6%>~w^+SQ+~%(UIrHju2(rE{|gg z1aS+aaZ+#yclJub51~Fp$^osCd2PJ?us-bb`VlkOdWJQyhKM1!O?S_0U zg3!1xnfdcY{hV-p@4=*+k6A+E0|xZ*VL{(0N34}j!TAghjgD zH9*+RKr69{dE*P3QM(;_9S&lYgMlRs&FBT5hq{_D7Ee`ktm{BQahWRNs5MI$PHMkY zK*)-jG^t*$kDVK?k_8nI08g3O1tP9>2E5rB-9t+~9lE^a0<-28jv5w$hFMYlSs~}$ zN%_@*oXh|Og3>%Dob|fu;R?I_d!s6Y4)fi8TB~t+-Sc?ZhscP_EcM^KYyp1+KMQAe z)8$Z@{W^++``&mFz8?`0$+wd*PAkqc##}qUS~2-gHpRSBw9w&Vf@N>Kue1i(t+LO% z$iryj;$g?Ih@C?@(bSZ9_EGDfDJNz=j6NPXZRRM9r{AN0;EgJHOM=$2YI3-dZsB;)CTjn#z1lH^D$7^6_ zvOtz^10SE@6C{%!FX~uGtR`Yz^OnG2xAG=}#pRbZZIg6*Wm>U@Mu~y#8JP0~NV@Tz zNX*G?GDaBY1FEZ5T`HL@ud;8AX#;;>4MM20BzA?=1dKSZKX5eOJ}<@d*%tAs$_g#(}r?N(KMxK@h!j;&&f)oWu^X)qtp(GfS#yMu<3%v&qq>{D5o zV6%(Q!J0O+qTgfCe-5voG5)_ zY^zYa6)p7re#?`RH$ABn4v$*9<#(yCR!o-;c5ra7doRy*!qSqui0?PCkQa`t)`->+*W4MNrJKLP({mzw5H{-T*QnhjlLyF_LUv27M!=(70xovQCZC`v z9LBlkTK3e;yZYgQjiVD1k74jOeVN+Lb0-q7yt#vf!ffeaOj{IE{$Mdi zfNn5B!sk_KRr z#`+3Au-x#+vhZ143mcpD%p+pMz1qJJokkkFD-@nV$h>g6_Hrf-AzFriTr^v)GfQ-n z`Dt_3*KL(#vc^8Y%J4p~_RGK$Ivkxv&{Lp1;{ijzLj=Bf9`rv+!7mUL_%Vc|$)SdI z?TsK7VHS$N1YBk`X*Im~L?Xjn2rzd!q`1V%j>Hns(#w@|LAd)Gt17tw{|eiPd7L@{ zmS-O0>}<{X%#_HA>Y;eDvI%Y*Uj3^_eiDh104jpq&TCXlbzWYo-Qli3GU`h>C*W?Z zZy?E!ND$pku->R&`^#M9)|cKjhWxR6dlCzd{S2D&RTR4+gY9^ys=F#3H}H1t`H+Ka zqgd{J!(YYgwL;ytvJC$!l;h39SNujTgQ1aNub)ybG01`PyZ>Iw}5(cd&O%Ac@ z(;4DbB|p0z(ur2otUVZ!q54BQf>+lILG~nl2|xXHe=6ccmJz`#9od1PysS?Ezssv} zyfULtV#@PCha%8HrK=gwIvHq#B@kL!F4LXlbs^GqOL~t+oYy03fTfiQR*>Cbn06XSO6K@Q;zXXoIY z`bs7XukQjJS~u}Q=}4MiDHhVsbQh^Gpl5tm-L{^h*A?G=RNH1!J0rHt&azSO7fiGU zT#-8`7~4%BVq2;`_**=Ri1{Rw5~qWLiDk4KLT-N3r02w}_ATBz^v#&I*b2OJY78D> zf72QHl2EU9podggOt^GbS}!TKdBHr`4u!h;YDcuVE$$KT04#hv+kfebhZq(!JM0{G zWy<9m@^gZ4(ru){Hu=bTcoG(KZ_fNyXv=m;0Vl{F3n-pQj3JJ0?^O8q6oRrSet;_! z{LYs5^NDZj;KS0r1-L4A*Q5$#oP$VRktMjQ|48GhJJSj65vTI*9rkbC;8%W|u0M(;$#4{4%mI^GoB=gl5Npj} z@*+}4>F^c5gYWLU9AbzgYzTqN82NN(7L@mLo;8k{914AjuN$S%OWH|y`qwXaxk!U8 zWa2ZThHnCu-TpXpa^a@_H2#8@o1My&d7>4ed+W@-O@`c>pDe2Eo(6?Z#I37cTlL&i zwx_SM>=xgBmzFZDtt^3bRrnlUe=?rDTK1-= z1bG*!g2m(jl31`8^#%h9_;A6~_f#1fuM}h>)w^mm(8b!tP~MLVV$$`P^maE*HD)m2 z2U*k|q9w-#c7_u=bJLQmK&F3Ol7VlVbh^L>_!0bTud4#{XM5LwX~`v}#BHv-b8Hpf z!i(I_QtyXw$9`j8v^Qd7Y-FXowh4YP63OTD5to-0ILVeYi1|%cBN-|v3vi{hou%QD z5A9IOWI86UcJm>ykoLpPr!%bWMrQDFwKz0zFZXTBfh^182LbbT%t)U#55T|7?sj1? zSrQTd%oh!0<>bV+*Frm$SxN< z@8~WPR2;r-Gyk=_F5XifSbSMyJ)}ri84$axcu!@bsHL){GA>qCPzG))4f6+Nq~#w8 zHhz+m)}{S$%LA7|Yv8PO{N~}5b4R_ z35ppZG<~HGwSvB8`uk{WhE_250ted4mzTR_Kre>5irTuC`P)WejED(bge#yQ@3?ng zMIu4sVgcqRZHjJXCqzxl)DsWdCjwZ*FzaQ1e*}a9;iMP{sD>XD4^G3@{zy!L5XALvt5d?dod#zXYa`oTIQ5_B zu$kDCGVr&4i&CH^z@EfE?jQx+qbJ6iRNykx$5EDm66W`rLe9TubY@P^a^dDcMo&sL z5zRd~TMALi;L@|V9>Q63pR-LUDHPwS;rKg7VQtvEmXz#m7z}3fGqh(-3X5gs~ zDrJ%_v8&HV>(VI*v^1FfUSjyS=edoC1+KRD*v%Py5+yHRdHF3I#0dCeTkO&f>(lJJ zW^4s9KQB=w`Y#WlVL+=&xKO6LxH;wXK-PD@eM*>Fy5q5AN`?rx%Baux7=>Q9`3vjD zGa3Zg0dim)Q6v9$_#u<&{q8)^JZb~#+K5r_0G$(>0wQD^`qGYIo7;|ZHGxMNQ@Df- zJ9ytc-wJnjFRJOYxIopFW$o_i6u)-ex;!cCx%a+edvRuue_zR6UZo7Dy}J1RT;Xtb z@29_ub&6jwN>`mf;vFo3TPyUNNLpoV&sAT^ZI2LOivBB8BvC{?2xSwgwY((u2H53$ z#GAq^9(vP7Rz2v=UoOb``vtDDknZ8p%6!waqSW<{A};$X=H^+qbRv9CVWaz!3kxSL zU=+{Qg3n?%njfb+zio*^huI3@!+KcpL6zAAMV+`hWhht>&cm58ZKhF;RG!SpwWN0a z_^3!8DBo-(iiZHRAr=b#qA;t#JEcSVe^tjwJ-$+-F#zjpY&r!KFhT$v3B;xrO@C1Z z`H!9d!&PM{B>CB*ARqIQ?J!Fx5^cW)OX~J(5dt-tW1t1_3(7`Qyr#iSAPO+YhyaVG z46PI_V~(n!Jur!$(r1U6@wI^u!SNwkwHh^> z`8CDH2!5U-_NKmbA-LId!w(rT4N8O0w#o0(b^GfumfP3bYHkJrF8^4u=&7a$QXNbQ zJLlwV^SOeI2;Dtl5zh!an`Cr(pd7rf#_o8pI#uHFF~pD4rM?~68McZg!QG{I4zgmE z&lIPXQ9|||Tg`JX=ee|{NcdvA_HXP^XzW>gt+Kmr+NF;#lee9-ELZI*>%#5F;foN3 z>EzX9bR1AcBHQSCsm{x_n>m&c&d}|Z{C#z0Q+3onHvB@JMhy`SCCRgSnCNtpT0v&9 z28vFp6VsV7g_-QCmTZRwAZb;c5`MaMT|n$s%V~A9BG- z5K{@~@bQ>;WRkT|HaA8q2v{w6=5uRr6>sTpoVV+w^YCmoHXZi-3rS~|4@|Y8yuN8(=j}ADj3c(0*aEf? z@q3M9bn96F!EPRGTb4v8eJ(;#ROtr=@NQ=nfB)5@dpS-$Uw0Yu$pxrhRJBVacDMVi_a$O%rmDRA&3qi?sGtVs38_$-lfk8 z*|%kKZ58`u_uXo)!!j;ZMf+;x$=WuZO2nuM7J^~vmfNY9Ga1{;YqpYbmU=rcxej=8 z@G_eEA-j?ICVfsK8!zcj!1+OmHG&I{7$LtVwYOC|KEi`3?#uR+HycIWbg>ETtG5ZS z^EStx({GK930u&G!G;!XYrVkFOCK(5{ z1#K&e3Hw}HCh5W&06=}seg|+Fxbr%Kr-%e*#aqHf;q#n&H7vtU7GOq1Yp9e<%@|*vyKJjqS&Z@_E zzuetJyDM`q%%IQ+NZV)s-mYX)=j5T$mYy!#wBEZT(WOVtPZggmK^jn&+x&>-a&(?p z`G<%QZn*v}rQ*ji^;YyI7q7HAt+%qax#4-H2Npl5CK4mI4$XqC-h1MoL0osyk{R;j z6p3_=-tH2|mr0|mWFl;~VhTv4=(7_FJPqevk(PEg8q&(;ER&ZAn{{er{obp-fMC*3 zxGO)m{eh?N3RwMv5_X1&D>8_0IDAVXO5u46e`5Q}kpF^~9JM!Dzc*$X?nk7^!~ntN_gy>2t>l3pEcFw+)9iQlbH#fPcPZ65uc`iJ2Qa=p_?)(}iA zOnq=v2E1u($t-iRvkB&E^q*2Tuj83=New$d+h!L5qtd6?H5ZK@B)3>e4UgXsU%QU;K64)_2#>vvFxTp$qr!<_K2=3X6?_o&FQItZ>HqU;rl*X;VHbPN<&=Ls!c^Iny3@dQ0LKgC4Wl zRhXpML3tU3<|tVy_uTHZLPBiwvq)@(Ih1G*G}?{ubd(+-5ohEdPJ(GF`Ki(9J1CbT z>biH_!HB^SW8*$EwHtU55b9HF}p2q>Jc6}7m1!Xh%@6&>S{#(+&CdfnMbm2?NkfaZIw8a57`5`;XY&@*6Coxq9JEH&z;EwFaf!?w6XHeqyqnkgfLz{iu2x9MuA zi`*zV-V-ao&vqe1?Y>539qa6AZ$;A^c6Zq##q@*uXgsAsU)9yPe4cFUZ@B95FQla^ zc^N*Vw1&kw+_&}m+UM*qsN388*jV3kPHsj#QP-jQi`&aOn?LMU0ibBD$x{EqL(zxi z$xFD+VJVoPqoBopR0czfB}v59nIQLJ;;JDk)jDL3AZuF_d9CKAAK;Zzez_};-XIPC zr76%Zo|w06Oek|a$l9&Xu%~nK37l+zCrovOxbK~Tze$s7ZjX9^z(&b!`VW^Ae@Zzz z83=?;;m#h7vLr3I|FqW0}hpD#`;K3CWX$8`mIo2 z0y)k_ABYUkS9Oi2%% zQnpN;Sb43FB!Kj6P;4S>dRO(Fs*u*kYG-=2TpbT)FC-#lZ4iAJ7Ym^}Bpx8DWp{Dp zfl5CLiM&1m_O8Rz^j(&heq6SK*oz4-AW!~by$)}kjiyn+f;FHd@)v+3o|W7^sVXqm zHTa9nnQ5dp#g}Z(Qn^bZVk+ScTw5LeiSD?`xt@aX$2ZdsFPA{<**5L9m1F?IP6u+X z9z440O-wYYCp5u$SG_8_&J6bJd6LL6zXgqYeiTRC=5EWA(`-JbXui<;qmocm)n6^6 zMePk~m4l)0iO8cpPnhyS=Oq0?uasBD(x1Pd%Xr*4Q9`by-o*aPA9GHfr?gAXT+Y?obeMRZ%<|P`mxk6 zm^nT)dr1pB1Bas%G3C$Fd}GOBu=Y6CUl`I~zuu043>y?o58+*n9@ZTrHW#v87Q(%F zh&UN|asVA&Oneue{%@8%LL-H@05eIC_-2LKxGoI`cD9tyfnG|O?s-bD`_-Tzz!xG3 z>ra!-RaR`XTW{D=<}}=F5cD30xtYKNo&vYTke>-rzAlH_F)=B(Qm^{{WraI-NbgNc zXJx{r=s)F68*WX+sGqaAVZ57#n;T4Tf=_fmkGFp+9;fE3)4<+5{Ifop&ZB^r6bS#8_?2n7&5<1RUTc zX0)2A?SnLF#O@A<$v<~)0LJXDIGjx@Il+=~3cj6z>l3w=&sogB{dKL;a1}p(;n$sM zMuPuGN0HPcOdV0y`;}5tXV>{Uvni_LY0p`!`AU+8G{syfZ03}*Ce27a*n3%L27jTN z$PP&fJ$B_VRAJGVmXhVvg1{sA>RU;qZ_g^nG~)pPrU#mF%;N1%!4gGCxa+?m4C8O& zxA;K7{}@6z%jqt}@l`-X#U3qk*o*K`5Fv1GzA?JV%}bTk@p{by<{$wRT77h^Ka=@viW zw`hxlHqU(i8q@hb0H7rE0LK%QjFLlq;j-1}l&%n7NKt~y-v$^q$2*|1893*)+_JbO zx7jJZo~OW7b5(%~u4omZRXO|@1N94jrG)dCfBQaaFUK*HZ+OMGbD`l%59v}a;JEGd zIq+&wbs!YOIxRR$2g=4|pZ|~sP3mq@h5h*#F;px@7JC^Ic%fP&6n*R8f}CPeig?4( z+thI;mRWT72+Hn74iOKfEY-WSutDtXuyR)b^Y#|Qu zf>$c?sCxy`4OzIPUZoe>Ld20d6>anew?=nfA#v@@kX=FzAxa!u|5Qh&5dD9Fqkht!(ss&qN|;XPwbu4 zJFa&R@zqBuFyBS>dWHpK+lhvCSbS@TctcxdMb_iG{NCk4&}Up#5r|iPBT~En8KC+W zBMUzxD|oq>wM~ArMk@Iwe!z&Cb~4XBwcV0IH|I!Uf{$slhfY#aiz4&!F?^Zmr@qI? z2)q_yTp22lK(BNyg307C9Hb@6pV1abwx59Eh;bWv)atQ+eKCo^cu&v+640V~-qF#O?+P7t6CfH!MjDRc{rt??2Zz z)9TdC*|<#U4HqvIPN4Xgu4YF1Sv~*h+ZG(QcK`1Nw|eze;=ORIx}0~TE`zJ{^ss`W zf8aFzkM0GAAKAB|3RUmy6IM(^j_J0wEArv?`tcy~k1hORhWIdfiKsu+t91zX_1OtL z{&A+waj4yKc=GAmz}=jxSMIXFLbscyydc?TYDa10OZfh`aTY*zpjuE8p^3=hHKI$t z#S;l<XWlg%QQh`feBfZm* z76htf1=`(ZFKll)BV?p!0KF!ci6kCWl>z;>@bmVeNG!zMMdjpn5R{{2VME_rh|{(_sRXoye>v!r;br91VoK zh{akM#U!a(<9vL;wx^`amFdWSRJU?FF+#DZeipsL_FHI!vc0N2u&&-h-tPQ8yuHei zyKml3&|VLo+E?Mbx$o|+fA!j}OYVC^?~e$#%!oLw5w@-jA3HWYa{Rhb#HCg{vEKU% zI)zU|fB6^jryn)$gc!?asIox~Xf+u~d*frhBOsa(r%`qhd|e7-;nwu%O@Ez8JXJ>| z2EN6RTxRLI+6oc;Ar{}80I$Klq68SNsk2@0sR1!gB&px8}uHt7Z+1v!Vmt@ zFPhyZhq<-kP=Gm`=)bMT>gOG=286@h)-v2NdzVDa^;u5} zZj}u0A#FRw^sfYZJNJhj1@yx|Xh=7FS1ZW>$0kw4eXA{B3Ldb~8>9(X1HoKAIJ}#l zP*hB~&Y(Y!)_}u5av)6b7LEto8)NHxIW;07`vtSD#`CfO)H$-Y=YNFoIt^o3Y#9d4$>s2(CJ+1vF6z>n)_ zANpnJf460ufUo-f?m~ZJDl!MZSCPKcZZ;UhE|62?2b;o` zJ+3bl|K<(2IsERlmHfCe9Z1tUGKGe&?Xg>(~1Ha}i&N!4|~qPyxj<~m8=ECLIcL|GCDjgyEKgnipf z(z#WM%Ji7Fy;;a*(*qr(zv1v3c0%o#`~K6JQ`-<%%Qm86rH-j>66bN@XQP{{Bkk-| zc(?wp(no#phyuSiMz)_sP>N#eqn<-m#6ddmSLir<8(>j0tq4k1{kdO8p@gfS%NMAx zF#oi=$6S=-@{&SmCo*Gb@+h5yinILR8)K^-bdhAqzatAH!I3 z+&@4tG=+?q!G&B$w!~Vn?IS)Lu*_ioA{24O-hf4r?q*5PpACBmTUjbDVlRVMI`bLU zJtP_JCQ(bI0WE`fM`1~X@LM10=WXL+AcpK-N#gp1P4!(oh7C8oLF-bvZ&JVstR1`F zmuohf+Ge5z6G@8v;E}+`xQ+qb-uJ^-%}@XbVud?1$X{-mFzDi;sm`fBtV`$BwN>pN z1+RhsB#O*#d=qYn(ur|wP>|hkb%5h#$=zFscKjO)yr{vSN*B(#=k8Y6|HhW%eT0I% zAtoHoFCXYE^jk>`fO!Px+|2Mh^5YP<fOR*;V;QYHo?)*<;>qD zk5|COiKb$&!+5AJEdjT7a{{#BhCVd>d;0W%l1g~A7;*y>BH4|g6h5B>V@PBC#1D}F z(-++=sz392XwQ7R$ml$NKqC)y=a$uO-Vz(@+qJ=m2?7M~35B+(YtA%cE*N~mcvR=b zs%uC9VXY9Hc4?u6jZIGuXF!}^T`{WyXQKbOAjS%3&qQA>jS1#{;R&)yb%u3f7sZ>= znRK>V>*W{3=K9zO4YD|blDG7A>dL*cZRL023;8Ob-Mbx-htD>n3ezBZ*502Fv)vDvv%D@s=%26NnBei@P9r@st3kLv z;H3ExvQ{rKm!Ug&AI<$sf++rJzGcMjRZFwsh_P&iN|DBjM7xL|`A3E zt3JnXS-srdKIo8kfZY!+5OpM2AvlQPeVRz(Ty_?&!eqQq#la${$1zb-34R zJOw>AQXHWdcG773#j7j6FUahs`woWQGlty*Cc}~ju*j8L5&ZL0GEe;Zp?Y{vhmYJC zqDO^B^rlkJ!r#*(CQb9Dd_`HQHRukgxTI!P5bS;6=?cyY^3BrbHl5}N{ z0}F?Lp1jMJ&2!yB?RT?Om9lw$(&Y`o`+*LsDdY_%+^mStbZ?~OM*>&zVE&wU8}B{h zd0``t*A3}@2@qIecV}zG0@TUD!F|L*f$9VZe?*ood9OSPEylL!7 zIXLxNr~-FP!x9k02mq=wZWCO!m-;dY;)_XoHk)7JV~!hWhBC|&+HCqp?{tSawO^(O z>JvWF^v5c2MODMc-HlZifL#FsE<#%L4B|tJqXB59eTLe-@izh2R~ebV@()3o-poM*Tm7ROhS}rb@=|8>yobQ6|HIL_ z$1~agf4uWKl1l39kZMXvjKmxg5{AUcVJU|RIfS_|Be@Gj4nyWF$IYoi*o;IDnX^&Y zD2JGA&U5zr^!xXI+_#%+*RJdRejT14wnw#R2QpRSDR;8Su=PsUQl&}i?dhx8X2(nA z{z~^)UlYo=OmVG#SaVv0ckAu5$e+${H1b^oZnB!)%EQIYJLt$)LN?u_d@oRUHPW>9 ztC#I18*w;)WS4rVGLOx{10(TY;02o19CnK3>>fHn`uA<-&Q*)V4yj&b>TE8)tpm$T zi*VI4(CFxNDYwL(!O!~JDNZzVE;)%pejHYD#2`3;)MdlnG|g%Rc8-6moAQ#w-PS_d zQ9UsQH8oFD=&7#QdXkhk#B(-k52NlU<7C_HS*SK@kdW8AA6{neJ2)^-+B|21BD$$e zA;U+yGUvqM?7Th}Q@P|T`1cXss)5w}bMox8HPS5SoF4@C)DW5GBNbs-qIZX20kI|f zFLk^JMV;{DO)}@==>ETS?x1y8s#D4(bKOWeJ3Xx$kT-7{VbVhN_H)^WYNM}Ct_Z+-8dlRm!*`OKOJh; zU9MSWjP4pAnF4;VssO1P@h9vZ`z1uWPbKt@#yePgs1HBi}(fo5Iuk zH8VMNBGprC##PHD_2v9ShT7Y@*j#Jn-R~!Q+YF2`7vu?Hz)cy@`T!f3Fz|yoTdoxHxztWmPo5TLB9@Lk z^s`)(39be3rY3)!P>~7J#D+rry-VWz`MILyRr4UsVx&cZqQv$RKe{EM6j~7n_)Ml^ zAZ~UwjP@cJrhuZR&VevE_v zOV(pf4G0ofhfuH_@IWEs5|b1K9xQYGKIyWH4fgbjPBZL4x|y zxgMhZf1^)dK6M`u5esm4{ZaIpVVXi!Gp{dH_~k!zz+hTj?W`oX=mCZh!(W7oFOo5S zDObP+1w@Wob@N7<>Kis+8&1%4#mE@LBl=_n45W%?5U&?i`!@KhMV47-nX$jzi z61foh46CEgXrU8uW6Y4|BZ43ih#(l7WAlk91&U7>H0{7mBfwXm!u)t~FaJk#y?xhG z^a^cVBlo;y3l%PK5X}vy|2V3y9fpblEIjmWZDEQ6h0xs#o;_mvs@uUc|h9 ztNrF<3C57p2-cvzQCmrM_c6!73`p%QET*Sru6iB|i)T5`YU)J3-n#8G)8`9Wk4{-^ zG*$9jBd(~d1yLKqaqqeKyE-oz&j&O9WeSMOg$aKWff2DRa2;;vIdesY%RxxQhat~m zY_$s<=4PI_nJ}{&hkq4|3~lPCJrg3xQn#~w5#<)39l;966`FaYzB%5v1cOlre0!3H z8omy1B*IFjp2B8;(70772&u~;9;Rz>x8A!{6NFh3+D6!I?_O4a=HhOf{UKZ?s6M!a zLXyz-lGw*|smP$Z7NlBX*6FH}imlIIyo3*2Ee-WaVLr-{x2kdxFYB1d-xcX_o7Jch zYnDj6safvK>-&{F&(vCf5dBP_PfxaFjn3%%&0eXgyLfL-1AAYou6KOv!$l+|UF)|f z4I#fJa6Lf-CZXdNd|Ze77RPGcx`M^8zyzS!lsKXQQP!!ttK7~u-V%6aZDfD*@(GZ6 z5Sf#e$(lyLeLNt2i@V)m zO^^47fc`~L6p$ZEEv5}|i=}P9?R!-ClFhskbx`>7nuZ}QVli z=@U`~%3lpuNc%?R?SokUckNArJ^6@gTtBb{=70<-i01`LO|5_QnpFlW(FhpeU-hLC zZFhTgX}T6?LEDF?*8Y&@(nAw;xQ19oFYQ0r2grTHIvf@cVLua2k8b?p$J?B8NK5!7 zZR#B%Q%Tu&s}lJ%MOKEked_EVByVyi^5jzeHmxVu&aEtctLVw1Li>Yt*?|t6Ot-B| zX{UR?QWYtI>w5kW78MWm%M&`tN$wIKzJh81p(1QtDfbyzx1H!UJx0IUi9AoUC2co> zb>WVo`lUd&Di-XM*Jo{h4PiN%K<-n8N&I3Km9)ntmoI%9*hVes z7W70|>OB76_KqCq6QsA5WkR8-sQaQB&o-vAZ@jt;U!2)tuz8C?J?0{P;tKTMg1Gvz zyFIzCJnMH5R(nVrQz>#B342&tG4Rbzc)Gi;r#ysy>+(<3Os(#j5-s~smMV$L6_2I> z)A4WS+S|Jv1rHEO3lFCLp+}?_C=12m8P+$K5Zs?9w1%XWe5aJF*1uf1xpI+k%V~`S z+C9N+L$2F*dV|XZvyN%N$I9SLl#+M1!FEZ)BOyf($W5Y?^s~A)ouy$E^b2zwnqL}( z=`xk-v}!s1`!#-Navpd2oUVE>Dy?X}aWa`l@h(H-2z&$ZAOtRpB6K_mi6bHIR)Xh6Tv<$f=LY_q<`DwA16y z81;){nfaVMVDRT@f?o`151_U`4%C>d{spxim$J*hUReq%k}erFG*oR578<{ufC=ZU z5Ig;MTVOZHk;C@)Cj1&*lb#lZlK2)&*)Dydn%1o2}2yI3N{sVos^{4et} zoSMQ%a_!8Z5mxFV6AlL(if;JbCmXV^5)Z(F73G=`rT_J!&IQ^nAn* z(!*CW75{bHTpY2SYcQ|>UK^tMA6A9$pcqExQ50GDa!JtT4iMbgawHr)J=3CFNIaFF zi}fWS0OP!1Qkq&>`#zkZDL!r7uMx_3j^ce0;0TlV$xV|!8dkSftg|M=KbD*?T3lp1s`Gl08$SP6-zWD}BJRsnv(Vx}$ zhH7WVARa03PDP`9d0_f9S8x~5N282D$i%taapJBrEu@sJ9DmRdKY=tQ;mErE+IH`| zJH8MoN6v^PWPp!%lv+2({_>sIOV+eg}w6aME<;jS$M4$~QHkvp$m)*Uby2 z>1;mO?iX9eKKJ>nLimX-mxL~BH#Lwa5sCtd@(n|+NTx)w;CRTYOgtm{OfMBqhaZx z|CM*sWqjhKx0z%k?uSO;d?fd(lADviFcBaJ;;Rq7pZNcZMQDtbq%RhXKqIa0Hk1B! zki_zXE;^1e%Xj{OwBDx=q_BPo7O2p&boy#ur<(qCh+?NzBC4t5f$XMRP6-}Kr0vH@ zl3sr)#D5uHua(_ZUI2b~L-gCuc)_AmNio7QJXmU-pcO~d|Ajq=+ zf#3J`f|WYUJ}_{UJs$I>SPKK>QML1OCY~VYuGjv=469{AZf6psTZWiPTG{SCM&ZqG z+cER5@Q%6?lYZ*Q7gVF&2I^cD>mDko8o=59g}z_Yb`hV!c4MJhmIqIzNox)C*N0SH zLyIe`@0wxpPU`3VC}r4Tv}K|d3Q|4e2sR*;+^tYj-FQWY!9LssLuv05%>60K__HQ zeR;lz6C+laX5LJJ5R86FFrs#i;ET}4@;{R6#+qSKr4+b;la+f1)!}BrnX;%a#0WX~ z05@>d7u(UFgmN&CU#~ZW5tR@heVnQhzLON5nd@raUAxHvT)HR7H-Lz_dbp;TDW;LZ zR1wmZv%3HX1Fg+BncJ#z&ZDPt-W6W6=y>9ZZEwydxKvSli+lNnG=!Cb@8*+*H_IGd?BvDw9D7*~T6Uaui`?K(}2?+9! z*keY*5B4tMtVeY*iBNij1;cN`iP*V*IZlo3UyT>&RlUb78f9%#!TW-&*B_H2KscDe z{SJiKL@rU+s^P`wuqqcLG^*!+CId^wB6}_iDCto6c4ZyH3O$Qb+p2amY_$$El(I(1 zi~93(4dn<_@`MsmYdAh^u^0D54sI4J{1@VS3Th};LOSLOMsTM=c@K{+jgSZhr5*{-p^@Br2$WCf~nM| z^_^qih{kQ?cgI*T%g^7(JqHiomI$L=?l2mg5IV?JVA0L zd*?^<5$gV7TdXQ-0b=XN^|moTNNJ^J`E4TRF!g0$`!|Y!aAB$v>0NyyL+pc;r{H&K z`E$L99pqF(kx+tRk7n*`$D3dIMHIz zN{jpU>F9xiL|}Ws;l`s=UECQELN9jqfZ1sd+*nA3O{qm2vRY5#F!v?oW}qg|?_ITG z*7I@}MU=**@Fd)b%)LwM?+U5{lJj-UkNJO_zoE`1qo+sOs3tAQoX;JK(H z-Ds-3Xt9XVHbU)2{_AW2E2*) zU{PYDfl%sTT{r`?Klmk`DKn8KJf(bW@VC+T^4jBKGx1T^%p_6BeI!s6$KT_<`89xM zR=}`|jx%WqKU12K_aT@>NO(=2!JgKu@(78@7U5iRn^s2-Gm*hm)Se*l+A)}kJ#IVH zlt2}<-v0J|-occOC z(z(H~Hzufpblvs1n0qvFzwT6q^0B^rPO$weHPIn7`x@u%7${GQy5}XI$ifXeizzb67S{KuBdDP_< zbQe{|@3cLprQUmH;bwUQ3*ZCJ;UM;!s6khKXM%qI4IqO zBpCM(f`^O3I`fSM>H@wvzVP0>y}BeU;sQtn6)=dIfJmnn_of#hvty%?b-Af&4KvN&8C zRtl@~(=-PT4X)saRx~l<27S>la6)dv{#ri~2SO+JQhykaIR>tva(}3YUuVBID$am{ zzTMY0yc5u!i)LdOZBaIEkQzsWT@*U+&9 zh}y-wJ<;~~v+Ejo=$7gZ8$}nFR`~mTZvnlG^&0+2u@$dlJXZSoy-Kr!%O*j;htNb} zfG8@hZJ*X`ZV<9>9ID$^cHJ@Ywz<<>UUmAfemShb`X@@^Zfly$!7;1d`exGG(j9+Y zWR{ES-}Vhy2$JIoOZQiN6w4x7D?HWAYIl@%L`d^;PudwWVhW^V8~B^cq5L@!NqA-b zfMReBW{J7W%7qU1Qj_<%06MuKnzOu|p~Mk0RSg ze0)%$Y5(QrfgqD`-^vq1Ou`@h9!&!bEWOQJq-x!&av1N{w-P*Kx|lzASBphxMotC@ zVg*3pH?=|4h6<&>x4sZKuLQSiXEKaLHa_0i!PD)JPXR#QsU zwnB0>PAxecxo>gPzS`Bl$x-&j7d^BP1nuYV=ZkmnoHz@@Y?ll5ZDs?>ClySR)Hu+) zVjgfL@`%k$b;zO{>t#lukb@<;IjN7o6-r%d^G_-8Z{v?-^J#C7*;1CxM@Efzd&%Wq z9h;c$8e#>AQOJv&!c)btXZ!I+!o2LcmHb>&F9|skwK<}IdMVQ9n7v%c7~ObSA~ymd zys=k>HoB)DODDf>NokX|mDKN#fwtBD7r=Gb2MV@K;t>W7bZhla@>KRHs&|et2_Yc= zl<3cOF%m<)F&((ZAZxCWE5jqzNm(kC5|vkj>(?p+!F zC`JJxQJ@O<_)>G;vy%Y-OWub?NxSX{%xI$RCX6%dWK#ge!@2h^Oky3%C>W>>iBkov zy~kpMzuE1@QfgBB)uRG1q9;`$lrAQJ8dn*WaSpy4Bvnh#d)g@n0U_IU$6HE!YE)=Y zu+7jP)@_bj|CMF>P(9lADAA(q1-r&pREb^}Z4H99?sYn}fBLTU>iD~Q9-VNo&ykhvt|Hal(3n|DnyMdi@ zUSblYE5)nlXb5T|lkHYSOVJt4r4RvCn--`DUNtn(OLj zh=smL4E7Uiz_pKZc!1UO@NJaYupX9OUJmS@$eE?gfW1#XnHedW{@I*M(5Bz^xmhsq z_#d~1gjgqKaPOVDF09XH8H0y&n^lAIIWE7Qd-;zY{{t%_@=gnph27n0Xm9s)em5cJ ze;ez@o;*>-&?OL+-c8qD=H7b=aockOTg!tY$VS-xL|rH1#SsA7NwWLhAoV9XpQC9q z#^k!Lk@RSG9Y~hMKBM$@lEKvr7MOdPcbrZBN@43`ja=A279s zzd4Jk?6>LFI4GB;fdNBHS=1xxb&|(y5(*1D&%MUstRL`j{_HML$|;VYjJ<= zO&}Ib4^=obNQHEzj+uO>mj04RwR(`t_Tw4qVq&2RbKpYV*r90EaA)Ib?kno_JYa zw1^8;8TKIQ>i&&PIu=c1Faq5|-Tf;3&9F=O1Cm9R{4%-f|51RUc?`-cE~q#&@i0m$ zcXD8~_P3|=#6N85u6?senF0Lb^?M zsl1(7Y#wY;mGRN~SNHdxUMs;X#kQkrBuZ1Iai^zFcKpF__lozPeMcb?;7f5XB4koW z5Sc3|)omhn;bvfD`!h3nEv$__8P;zoCy2`aGsH}M^B-dDZSyq(Xy^~Xvz&4R+5X!G zPCS`dc+D{IHlK0SzzrYF+h07LX?3}O>y{ClZ{`AiKNMAA^c)f+K2M48rltP`Bu}## zVJxah9k6to(TvcmuAzT{#%0t#vIWwkS<>7UwawnYk;-U=^g&tgF23shH>&}*NN7ka zx>uwJ={0u%+3M}S56|5=3^wN)-R1c;7M0*gY=|K36pVOQ^!*Vy|jp%Dy&0_6)o-*iqk8bvzC| zq*~=O?s&>yz5FkE?K6=+GBwcD3|ibWr*)l#+sH}P>(|=IX~AN=7{QVLOwPIgDG9qL zHZX^G0*u&#_|*D|e4MXP3;jel@AA;~g`=kSm{^Kpu`1kmoH^WXu*co#>~m?ZNN1tc z0tfH6`+7Jc{vm<%uF@uowW(H}t;aOC4)HkN9P#tDkv|3&$azaWrQc86*T2%nLldh( zl2BC@3!bF}#&Eohy+Xkm?_%fDou}Dqp#%fT>u0@Qz=datf{E$6Xa+FU zD)}ppSdSw21x5FV(W@u<)V8X&8WdQbp};~b!Fj@N66ZD_>(M0T7Ir;!Dma+&$;whR z$UO4Rz_a&bs9PWJj4b`Kt)T444Z64zVU46OYG(P$G>yji z%M3yI4*zX8hylSh3AibAc(wOwuEW;O%k6J`JoJ`?A{*6tr@R2yt-a#~#2q@a##$A+ z2kL#5w--xyB)Qf{LW5UYl!1&jd8~tY``t1)c z*2Va^BwbErb)^i}!Bsj@k^PPVXV~pOd-6FJ{dG)j%nKZE|5SfoXI+V-JND2z=>i;3 z7bCSWQZPG%YsZ(OWLh_SYwj>rnH=1?pGGrTQ9(e@X<(KQqb>RR4bc_eM>(R+Of<9h znNamQ0}B2U-S}S{XQWHF4GmUlIbpi2>&5gcbx8>?&xvUFWZ6F;?|mu>cuIe`KR;Iw ztNvK%`QyRkhSOV8nho{<=$OCL#@5%mpe;3T6z)DWNzsmkutqHWttAr~DehbK5TlD| zqeZ-U8~GI|PN#m^J)kq|B1`PYSJ3B9<@S$inSE<~)01PRo8H3d_YZPKFl_M9JW*)8fjoot&eH9JH8JD zp`mQ>VjMZoVI~JUXL1b8<8hdcr?3U5+_LkYr{AtVd$QU&s(FXYx6cU8RgLbE8{^Dv z?)C*N#0&P>bIkndeQF_kT-M8Cq44GhHn!?m7VM&9nd2RcyX|DRC!fP|oM5eaaUg;Ts7M^($Dletjz|avo0Ax zd9{iO=?TD8XDMPTvi`>zZ6=-r@*fiYK2PkTi`_AGu^&MfC5% zora_cFX!xTXKprTEHlRCpEAsg=9d-p4vv%b%?^9hu4KMnFN(Y8a+QQVy{^8e#JC^wZL^<{IL0#+W4})(O?HEx*s@7TH4es6S~8^Z zEKtK@2`$L))I8NM>dP$hOJD^P{$;01anL(9-=+_?>C~{>Z_Wh}=5L)Cx#&ChKUv}E zQ-GFzUDzJ;9*}oi@+*?M<+@j1&>tkB@CrE&-Sz}YrU?t*z}ul{zfXP9u6OCD$IPiK z8_Klx6z~+RrqbRpHYo^S-?eN`YrHp)4#E{VE+wD9#4t7!?JkKAiXake%7nT>zwQrN z4jz)Q#GcOUCP|*LduaY{Xw&lMQb8u*AuBqooJ<9n1cQtW;s1rw1h zjSMotu)00^JIQOPGcCf3|x*sqCVj7q<>c#$=DF52+ib{vcirHyeZ3rZ` zg6M?U{+U4ZVUun5??jN&Z6`i9(^uZ!&2>0~?eId{Ts3M7q?MGr(Y{F)vdRWAoziCR zOP8U(-xHbbNmi=ghSkO>{?qsF^cE>AHb@metUWCf`ojuWhkP@+=PZ=rGtD61BxI|6 zE@_@DEqMKUwYf!iRF%syA^*_H(8@-vL<`0!Cx^3Wg7en^dQ|bcz-4sPyI_!C2G4sl0+T!0g-F%fcIr$-z^>lGix+{>{S|?}G@hx7uPW-_Wxo z?7!1jwyt+jgL0Hda4(ONYZH1D7p4 zel^9qylXrU_xhU0r0R$T$yKkcb-eG|ywdgkf?7xK(^p`pzAWfwukn)Jf@u8G| zLc=ok$~il~cMsIePugRSV^ae+{Uc6jaSgTKHQGf#RZtN9$6POOZnTbPh}ch@{OEI& zn+-yMb@uWF{yGxC#UvA)&n*z+5}xg^Wpn_K-RLaFGjL+kVhry1xc^GZ%vIsfMJe|P$~->N;l+*}Jh`?#0(krhH-$eJi|Kgfi|{CbN`PHG=2EsGif zoH~3a>}XNed|~{+TBwaKSs@fOGzx zKBOyGuU6n0!w=ui$M5-m+i+eB)V@uaivMX1VPENhky+Z-H<>kDVMA#r<{m^+xEYX+ z1LhT)u~NELXO%H|51OuyIuo>@{>|!C3;<7dp;8@*9T)oC46cDR2!`|4TdETGogO!| z*`!Q6?W6vZ%Y9S68Rs zUr$X8v)*=WcZ`mV=@uGFwP?P>#GlU|x11$bYa?;bck}2^hGnqm;?$u{@woMC5xb3O zqI)pxC6f?A$lQAtlxtV+5fPMBkzLd%{(;VQYwf}=v@ICtLahmN`Z+-+|J=aJc^#H`o>HItW z#aY>Y7DSPERZ+4E$bszR9Uz#mjR9Q>oVkKLOJq1x4&>BgsV=ot_kR@_Rd`k@vCm`o ztXeE_vm47H>Vhi~aXe;rTt8^%3qEX~3j~yrJjnfc%p*A%)_tC1aLQBG@j?1M%mfvL zB>dhwS(x#hlbr0IUc9;X<40IEq7s+I8G%0n5TMj}kJ-<=7DeP=A@8vH0wwwbFUG>h zI2r(cn6>~crGZan`bSP8B$B0Vl>|VI!!L=%f_t4h)Bo=VxhN;dR0&^y`mmMCYbhsm z6avyg3lenAc%^_=@#tFjRWBYk1+!+XVW%gjY1H9`icfILCEjL<<@O+EkJqkQR-^on zfD;w2?T-ROSv2v{yMR4sg67O)K>UseKEinz+^&16H9ozHzeVQ))7V6!8wv;IQbUJ% zYcTwP*21s^#!B_DQhE#Mc))t1h0W|v9T!vGBMnf$>IY4|V1(u)y+VuVLS_RXV&YRy`~{Ir4F?X~RPInWgK?<2ol17v5Y7bRlWrhlVAVO^9#) zqquY&Df{p2^B&l)e;qPfI;d>oPIW5^G)(W-y!U!&XvXt;`BoHXK8%^@uRl`r-g|IbIrCA`dzE$s4md@BukGI^|6wBf{)SmgV4L1HLz=B(Dua8#IsyeSardB%k*8tPg59;E%2i&27UJ;$C$uMgBw_*>UXaQ2??cYcL=dJqC z=J4|T5A-7$6OEx3$9xV;S7GoRdiy}!7TG<7YI6}C8dA~9^?%9QJUK-f4 zrmVFYiyssF;}dG0rkzmF*7ch!jF2BY0;Vk4YX?^7ryl@$ zjpB1%7(l?Mn=(GxuozENnj;p3vnWYkF!Om(GM1O{1YJAZjZm} zcy#Eiy)b_c-s08kC_{{=gq$Ssh~ELCOFSu^O%!%bY#CCWBVxcK*AJ8o8Td@^RK$Vy z_aW+6F8r>ME&%S?oY30#a~Cm*NaBXM$4p@-_R00>9W*MrLv~YoSpa~qJ7Pl=&AnZH zI>MW)FVEity%ziplU{H>O|9tUl}2vsxz4^{nV8X0$t8cH=apMG4F__by#8#|?J^p* zycqOEVSXF$IjRD53n1~sUd8xi1O5UD%;BsmzJ@#h zQp62RCiRMtE*hX?0A|F~h}KhnULd>&abrbTG||cbfV(o2>VCj4=ttc2Y%6d6M!T%* zXaoC3fZ1>jD3Nt62JL0Dh`X?W*REW&w%Z~+ihbyt_&3{_b$xMEccsB5IpXJ{xZ4cLMM623P^c+mtr4;4Wp zaI{#&;;zar$E1{&!W72SP*cnV35fxGQ$W}S{od_e`Kv#I>hd3W&*XFO1d0@^K46o7 zuib|+C1a>1>O12mMp|a40hwYuh|+$ev4c%n){L+n?Fr2OFqDv3l!${NxzZSEzs&y!T6`>i(!9VP^q z>M-1}gqiF0DSw?|iO)T~o5|Htx7dcYY1q^ru%!p2_+$T=o>Zr#Sk}B`rwzwhkGlJs zu|(9@R;?6_q)iwss!-1G3wnf~}RgTPAiL4 zSK~T)gChg3Jw;+)ZFs7{)clgvUk`RssNWk>F8F}zG2UqZts^5=~y4)5wE%L1n z#}W|)OXecIFy&Qa5Mo<8eYI3Q`N?``t8L&6no#c7?4Rg#U^BF?7VSylmW5n6+Y+P;Grk!1iiX;>&7c zRde!B2_GGMO!uNo=StypU%`6q_c|+IsNID0kJ5K-p60g%evWhUIR~-5&)%_;=Q%N9 zy{@nrqGz(x(PlcoV~qdy?=wTFHg>xofL0Qx0LZz{zB?2gNYS`aF9zKQ0K%rIK;q)2 z*kNLqAs8^M*V&yb-4YWNR#{khrKBs|4`Gi)Z6D$bls&QL^+v<4re;@HPYD|*O|a2N~26(Et7D$)*!#FG1R{~ zd^F9w!*XfwC43(?z@c*A(?A8libsPS#Y4}Sf~xTg{eawtd?jtW2&5E^VG<{RrhXMY zBF$xo#Wim4@);j_*v*5cm|RE83CuFJr|AmZ>liS*m^z`+gektqb|>u{wJ_IF-vQ@PFPuyk5dkC zn~UuB?Z@VEGpBo3US`Oe^@>OZ4k0}BtdV~Dd5zlS(B%QU(2b*q21>NrWWyMoP_H^#EI9fb8np4bwUZ>ON<~M<&t4s{^Xj4 zC1E70Rz9+Ny#m}fHL2SP9Y}danO6!|LJEYiJ~=eEuF%6)tEJ1AQX?%m-i0wPR5N*x z?|qBv10HuDg~Wbm5BH>nx*FXn4^I4LUO+ikwV8F7!8=rsHj^dJa-9A8i`lz_p1Xun&Y$(-KPkeeRzxTsMM-pHYQ?cSEWDjBv;q3psYWPA|KD5h z;10=7;2$l#5?+9&%oDvOL&Hf@f$Al``!(i&IuCr<)?lwGAhkFS`|BREhH>xwc;L8_ z$TJjowD1=IrQH`M>68JfM5Q-tz=h}yHZfVK> z;Us~VdB>~Prc){;e~S71Is+~Yb>AS;#`-)~Q4r#e4NQ$tC8Ht5d|Y5mf-D&~u)*te z_vP8Y=h|FbFolz;@zuBs68JR#qVAYHa@4J(UuJn6Z~#q~Arx?Ki_l{YaE@+L+6yvyHAv4mcxh)N06pb9G(z^E*> zPm5SE-#u@!-nE~|5J^9XR-6O5me1IW-uU(J{3c9|-#ODjC!)Nhi2WSOb4c|6BWhyC z+h)oO$g9G~{hQL0Z5-w++UdT7$UZFHtiIgtGv&voGV3H=yZAYzzDo~|-E$@#%lwUA z?BQ2}WcWm7uuL}n$RzcOa`J(IJYdzRx9la+Qy{t zx|NmweFZx`(Wb1&Fq9vlzAq=LeeG)ofjX>UaC|H70=&FfGdYu!pjL7E>bTb! zSn1WQ&=UQIoQGA*51Ahcdi~ebddP^}JZWMuBm;0X5=E41bLg1Xn+Il4z+4+pXKMGH zn*S0b4o}Kkd#d2{nc{V^MOpd47&Ed#gzw>*;b~PlxHx>3=cO4f{0zLookJs1bESDj z;9N5=cRzC$EuH+()Q?vR&bKK&KQG^pRrd7)N$3u>t=N+*K^(`->D9fbbBcTFB$24p zN(^xhsoe1G~zHXI)+w_;7^iQ^T1nav-=2EB)tyt*e7B) zGNc}hO~XaY3JWg(im$1=-}&Jv{`&Ruy07<@8&|VFZj61Xd-_4s>Rsm1YHa*^VQ}@) zD=*LbIJDj7tORq^FyNRKmd?F-4u;ZJW^7(6)3?OeT*s#NRTj5W5yX#|*~*~k$y{dc z-mkvCdDK>Jp0lFZO*I)M5@p#GdC`U5)|*z+EGC3%HAMx$zePav1vS4DAuB^0z?ea)N3kbktW7kBGzb400+5x{ne4kGX2oi^~5?}|PXiC^t) z?XbC3)lElp_dn$H#0;|r`pM~%%fRu%O=Fkat8I|nQiftq-BPbKRP-+@A_RXc#qa zS}qCSpmP>JV*O{zMONtLPfpzg%|r)u`nO^LJI`O|$h^OT-^F64{VUS$R>zNc(OiV^ zB>+s11NUb@D-*#DL&C6so-!(k*Uq$3x0zM_#{KE?evtn5@8V5e67I2Fa-Czw^eQB0 zv{n;6h+Lp|TpdjyQ-N4Myy)jV#{8oqP!*{PH^k^Ii!?Cx1cQ51z50X#N8r7;L53XH zM};cN#$qovYsXT>Zps-Sk2#z%SFQalpX}{0aDQLske$ur?I#}lXs8|eB86=_3@eQ}QyX&@nLqog_z!pI z$Y@bkF*hrjpZnI2eWn}AaZok~!+$>+$7XEG-PqB;$uUo;27;}%!+nzrC2|I|c`rkh zalgMt;KKHm9_oImNd?Om_ogKW37y$E=8ZqWPJ0anxd!)uAbz_^e2PUBWIE3o0Lf2y z3XVPyP|hV=EMubxG9GaA&H@w!>tH87E5AOn4D5E!yLMaDCb4yFdZD)WGXpr<`6m5 zoUP@sjhs&#p<%}F-S^i&^=FT5pZDkex?b1yyrR-)lPL-s5(q@EX>M^{+qh63$(XUE zp^P47-_Ql^dAa15{)(ISJ#vbi&UppizL2WRl5W8;iu|X59Yt@Z=)>fpjf^>M+d{CB z#l9k`hvZ^c4Z3+Jq+3&%ix-F2J2TAt{eVID7u%EIW9Te=HLw|k_b-Ob69|@6;yGu+ z>y@K74ArfG|(913=P}Z6m@&rX5f}gTcY*n!b*f1 zvP>N>(yOfY`k(I*k%p^*KKONk+jf>ZelKMXW{ZwjHcoXECLt!i31sKSp>Hg$aK6%AEzk`H%W)1|0J^+J9q2cCHUBLFMWm6Exh#ri*OzL zo_+7w?PKX!iRA()O$z*FQZP*}B3z|dGA?AAc$BdVP0wl@K%D4mH6-$wTFN= z*6l&Dw|c0ER%F3Trj$p^;xCk@*~U3gCnICk0)gOi8#%dZcL&{Pt4jtm1V$FwOyg9k zT4jj)=~cro*tSi1x`%|qBY*AVuE0^2sdOJDg{GMv`;YK1(*a8r2r zx0Ll-gKk$Ih*+gcOs{Ctk;(?Oyf0(@=VScFPF7(jH{i5i40*_9IG_ZZGfIaM(Y`M; zTYXz;7J$JL8)t zZ3dn7{95QllP{YAbc*i}w|%B= z+m~G~-r6?BqaUD}9FD$JO2v-)(NeJ*ie5iW?BdC{n!k{@lY(Ix*qK@uqxMeR1#Sbt zB;uDwrk%hi7z>KMigDzp#2iG4<$5QE?1j8=2o;|D_iosAV|nTXXohShs%S+Tp&!3o z{*6nAFb~e0C>g5tQe3kFNzRV(lPv{v>=FK0LIzlvee&&c^GbgDEFencsye-{JXIo$ zizDYJBe)BOFh=fm%=6)MSC{7}%}MA-le1-iz*UnRNO;!er)&>!wT5>4Ky01Zrj)%XD6E|BtQ`*%9O3s3aVSy-V!H%5V*^|2xWX-bU(Ae z7o)xKrXF^E=y9rh?pTTFJ*^ANanPcs!&w`um(cxW=~p*0z9d!Ix_?~&C(1UW3053D zK_E5;Y%Qv=*%sW0=OOaE-5;JmTIgMqg_KwfH!{fN1`j=z2qm~u{s6rM3ZhDgO?GU=MowYt-}n_3o~AMwAGyeBKAt9Z3M-Fn_Ok z&vgZ_E6WcS%a_qhtgS;~2vQ4~b;l59Ezf0>FT!AQn$_qnpBB)XU}E!`$;jE)FNb*B zMolI6m6gGvzYZovz2UMQP;<=A+57#g@2|5=?Yt>%)ZryDhmQ!R=@eeT{WvV!3!>{S^Rmpx;^DVEm-rX{tp z*+}11iFra8qR02t}q|b?-+#8^KfNrRkR7R5`GK!3Z zkyZ5iJxW}?UQMKPjd047?y+wEHsLpq-BweV7+0C=9o>K? z=~(G*#x-QiTC?tYTc1B89OmaUdcWj}^G~MVP%n6@jHt&niiVCOtxP)8t1laVA}MJC zu#c<;1Ab!l(n7(C0%U*;=5{U6( z?{Xm}4f7=@8SB^S#UTE7u+S_|PJN6Os@{d778cLlG)k7Zg`vIp_NU^RRpyP~M034imrcJ1tx7-G<2b|6? zsOUODY@>rVB>{)U0Ys2QO`9ta$F}MY(uw1VEcbL2V12PYTj4Mcc9iC4l6`JN(O$=v3^58Ad)zvpmfLHR&-uf@ZTR zspITf?6qUprP6vd|CYY&Yy4hO-!?E?Yd8tM z-DE1&`WO4I=H^Wzg?d99b`<3(Zae^EWZtbLI=@u((-Rd$!4S0VT!j%eVke^b~6+y^x*^1x4Rn33KGDk6O~ zff@+pm_gWtjdNrty)5}bfljoc$jneM(KSi1fE8B=U(IOHI^!Z^G}F&y zmIQ7!_4q+&N-u=*3_lwmkGyIv-A59ZTDNLdqa`yVWQqxoYvI>W;X)tVW<`WSvv!Ov zgTfxvg)t5h8CBRHPf)glup|?pn+(IO8yURs=>CxBWJ1;lmE-&2g82i+?5({zJ3y>% zcB@-^ZQYzSG|eta8#CHD%=Z>Uy@R?y*Qw++jxh3qKSZJmYxTFRIwRKMTC6+7diUd1Q2N z#1|R`l-M~U=UU(BQo}8^H6g#*c^HYgWwvq;xj1NnBToxa>z4u?82%jXH0n8=MUSa9!0r;go9T$4zI)Q8P!i zrzuZ;yO{jbo7Ac3cCCQHV1tvJov^vWxhtIe4yf?R6j0i}chO}0NtGygeTW!Jo)VlT z;;`xQiM8ZDAkT!SdQ3+Aq2@Zb3294{I**GO&gp3(MJvKZPj2>KJwrLU8Pv`7;5%f< zyuD^6wPzT%TFYC3QcxV|z84W?Ir~NiEobw*B|dlP$LNnis$}`QfUly_>tDp-BEppo zT+~Ya2xFm-m6b+nRYg`M^am~8SXI5j8C-O1a3RqKjhLz z8GxG*I$V)toi_AyM{VC1AbFJ&m8RG;i|4BU^qd=KjDl`)MDN-j#ob9}S00TgwB^{( zQb0L(cuxD3Sy6fHwI(aaFvRBlr_c}pYV@Dnynr7lyF_}SrnEo~0C#}&PAscqaHHI|RWl3MQ)U-#u3k#@|7KuE;d=J2**HMvYIj%rOo<)Dxx|BR#@WQHyb#qIaWf zf(hubF#1~$O|&ViouL7f3T5&m@laIuGnAv;b-?bh!rPh@=>d}qx(kfE+d(4p6Pw(B z;X3tta@hSpm|gZ}IBdJ*pFPp|Ze$2bs7k5FhGzdFYnj+W#`6-dOSJ5rBub*J8E< z`9^m)rpL1|2B3fLS*`5g5ee&=;65yFod$Zhi#wFcTCray?6?X^$1yumFHtFY0x_RAQTP$FgR%YDy zYfW`A8z+vI@P3slmj^i6`g|Yey|P+;>hM-R3va247lX&?_xkiRsC=h0_J;NQ}F8wOWoaQN@UZy^` z`dD%`DQbC-Dv@#G@zhA?_KNN6U!1&@g@TS83xq3@<5~g@b66Zac{uG)b_tYK1ugV6 zVb!#b&)TpJ=Sb4+*xiP(1@OYr!VOvVBG*Ftz?Ur6t{5$z_TNC#S@Z_iKGjX|AqZ6K zh=UdH=F9D4y4XT1lXHcn`jB1>n^9Wexrhy&WK2yAX5`+HOAiNer9i>$*Mp5_e?1B6 z{5wpYF(Ny|hOW9hrJ;T90`N5!^t|=>x`wpDOOTgj?4( zRK)P$V-b6SlPC$V{V3nN=^8wY*f^WBk6DZ|YQ01^Mo?9dQ>yT;1ALbywxT9R+f@t9 z;F$tgiTqMcG4HgXmn5FFxH#B0A_`+(DR^bYe>OM4i4;Y$B4pK^deEFLYGRjt$2t|d zGN(S40py_>zz$F~Ts|H2eWg`b#f5pF=X^rm@7K(aL&?S{OUZMxPA6==pT1l8G53?7 z;;ts@#MtGe)H5_O7|eE#Qr9>u{GsydPl2irbG~Td{Ew3*d9;kSEhV})?ttdoPyqEZ zgZwjP5TQ|*z(NfG1e{Yo(M1i85@gxJEQSprkkcC?FRj?Fhtt@D*xZLmI!w_DW?7F; zk8z9Gwgy+%W{{@liFDprk0vXj7K}F3?om@-v){VKP!ogyBg@n|&$8`dwkDDgNYP)& zTKgrbV{%17vnID%@4w1zHQO>#W^DL5W;WVmZCQc@#~P zl)PTC_b0R+L0g4qiYzDtMpCt(}GQxaKVU1ZW2@ZsE>G($uD+ zDJMk@FT<BQ&NM(klm0@<_|E@2UZ3Oo?TkzEXOMK+|tlu z(x_S}D6?08H5NGnsds)#6$*;jsJl=w_mvE&M@pWEc~463Du6Jl=*5#qJMK#ZG{)lM zl6Z{PH`zmm7jwLtPVz=};e;jc`q}9QQY(7;T^#(?vwm!+8=G1U+4m7$XldU!BvE}Q zgWo3+jE$pdsG1y|IFS_>)DKe5W@MmR zI}Fk#Y`-Ul=XevWU_Elj&{p&D3K)(0ZWGRZzQa)xFqUqD#W*-pu4tAgkO@#N*jLAx zy|NJbnT?bW9a_;S+ozzVxfmE2S623SGD>T|QAbv(R#vc@zGl1+%Oo|b;<8b25|>Qq zF&i;}cwPFc)cNF@7eM1HrAzohD3X%-S4PfXk=%`x0WP?|EBL$nR;+MD#-#;;OhYwz$RNXw-gsIaS8L~18Y4lDc2bW|R{s-&;P!xC;xNPQz>PBZJ zFj8)WnRR&pcXIPv)5PWeatlPKA~uwDi7`6Z&KNLhco}Ihr`OL7=|+WcHznSoyZ;I0 z8Wew(wy)(oAOU@#Dn8bCYE{GrHo#%JIY!J@n?6{mcNP@fCL@V+-jj8_wn1HsSQOns z`}8zv;&@cK+cDoVR=~Z=Z$UsU0wO`CcT+S>a##|7Qm2%D;AgmD1sD6?pz&I(s6A4z z?Ahnf=71`1a%&A$ z`OPNIt-D`bd(Q@Ap**T9AV0G)$9!0oBMopkkFGH4e?b}<7tZLq<5>v6dFp`#s>69@ z7o912!x6xDoHPs4q(t^x9_l(hE$C^Bm*;6PShoUof;cV&f#|5xiPXeO?4$+DK&+kZ z#@3>#-R%S#yApr}`zua*F~jXiow*y>JPUfe7kK4Rl8I6gnwXr?wx$XwW@p-n*JSYJ zRX2G|T8z;X#a+{YyPMs6{;hveo&4bd#~}XWs`z!H5AD3XVT{o|`l{`}0El2SYz>SV zkz(R$2eWbqR;8#nUN1SIFeuyLUCZECx8YYY&Y+q6s~PAXIy3mOLxJNuh`7oP2r`ML z?!mN+NXN{*pZn<;cE`q}W!);e7lgf(buqzq^g{NKIihWF?!pUcdl&}wvSoWj*S0OS z!q%iq290ZVU?IWg%Imk+#o(0Nh4ZdB^KlncnDM8adzB zyT-B`D<^%g@H$%D@|@bNzxsKRy>vzJzrEN|qEC=XoxPGAkKd2<5kt@6O&8hqIj>1w zsno|!lGU&BCqNcd zeZp_`5uk4$g+QwQRy^qfI14ACt;hdjz4+|b(3_>Fg>wa*T!P|n2{f2>%!9sEJnuTA z7IW<5bo>#NKnPKB7c`*d8$1P-Uc#q9bp`iqXBJH3`{Pahv(~H z#8GUmSkiaUI|MEl{F_pM3&?57r^;XSs2HZ@sjx|gcxvJ``m#~QjPrv(-N^5fqVVmV z{qX(Rmd4|35p|-0VlSwnrnZ%FjzmP|hF=N1QP1pA@~V6ZO6Ym$;!g=9NB&S(B;6i@ zk|>X1N8IiS*HuF#<gc9!Sc6 z=jSbX!&Q5_w)6E#%YWxC|D@&i`gOm&H~)J<mjjWP?n6n>*>yq)aqgZV@&^vS-IAe9o^|JS+qMi{y&wS(} zLofg1+dncl_NxCs5^j1#yvm{7i%LPKO5A&0>41$tg27h;Nab&KqsLtW=@gp~Ci;Oj zOh&}bMym6g&M8IIGYaOe7-EcU*~9`~UCCn6klnoAprxS9ED#>I7E?+FW*H7#_`OgT z>dV_>)_bx`-|*;HyR3ptG7nl)sgJ1&0Xb>DGS*v%pW%>F--MBz5kTW+yjto<-rF>4 zA{VbOn}L7+(bNm+u;cQc=f6d<6NuS_^sZbwK1LSrb%lS2xO5|XA9dXd8LBRc7$)bh z$p*t_2FqKZ4^e`)NZ@waMt4Oc)IlFEsFf>dA#?8bO06(n#ILB)aMY}$nq$Lo5oW)L zL_4lZ<+^jbtDp;gAOFmi6c8 zHZr1lTf%*sRwgz*fHtY58e)K(1gT^pGt zXgSmcB?yE|*(n*QS4)mK+{}RUlx9Z0GNS(cvzqg4>-V)#?rqK3u6Hpboe3YMKluE( z=P$YuvaeRsEL;2Q!VlNRfBNe##pCZREm`eQ(7|r$L2&?h~ui`e7s548}b3)XEQ2cT#5p_YT*I0t6sc|x~UUS zPWsT{Vg6l#%l<}2M`iU#;5yh$6T4dU0L(Ko4#X9!?*D!%tM*j!^)EZ_I4AwId^(5% z$UzXx-61(qDS>?*L5n#Ia*o&V^Oms`=>&6+Qx$zr^4sCC!>A>Rd_pFb>Zic4cVRkr z^pjEBzaTQ(2jY1NqH?-{zY13XsNSuJ7$qUev8R>xuR=S&bh$kE7DJqy6k#G6;%Tom zzL`EFL)0)*;T{O;U!|VfKV&tJT}n2upSo5=SexZ)pFB+k7{Mq7E#?${gxx-cpQ$Vx z9kX_eDSwKx9U!ZV!mDu9CvO5uCh?s<0Ax4->R(v9X)Gspu*r}WOKuW=*NJYVYN`~& zeaUARYYhXRb)V6xr#q8Co?ogKHk>Ddvl94LYT|K?>*1NxK0}^jSks|Jn<{-0J~?12 zrm*<+I`Oah_=m0ECw$p7zC>kA;` z+4iMndS~BhAv#=;_{TCv6}iAD9Bq74xf84AB3t+Jx^-oB}p><`oQ_WJKnHB`Qu%*%M<}=zbPo~t0)Ya|aM8C%K2^j~FE6sj1GEuAm~mwp(AwOzors@>YIx_)gbn`Dz8FFQ z3-te$r1(L48s#D4CtJQ{`V=tzpK_^ZH3D|n7@bkOYdnn2??GTN66Yn}@nWq^aG+p` z9~Od2%^d;A?Mb)gmN`5-%<4ngx;Jr(tlkWe)^AOXF(XXR}g)2b|`-dsn z1=6e3M7@1iWp-xo>sE8eGj2+ve#f-C$K($^V;U#8!_U}rHh+ek@v3guJNaVp)76y41ZwI?IQq_N%QA?{q-8KAH3yIU9&c7+dELO zkA(*e$C?dZCp1jqnPL{mlsT!7C3-MYvkBsJ32E{mDy`k+IFms#3mDg54UTH`XkgGc zPf8jMUV_)}DyQ`vb>LDSEan2n{Pr#ifR-<_gKq*}p#%XeVpLzmHq#}7P2MCl01AM> z2-vbugqi))KRQ1#V!XC`xjKd3NWM%@d)6MX72xt)@p`KH_nTEm0-{O9o52n!A??gl zGszc{z)`9_h`8RBSdGrsw`Jx@rHwKyMHfw6n5zB|V}!H`Q;LLR2~IGyZLQm9pnaN( zn&pp&`68Y6ui46IRL!3(LQ#JS8N{Hqw_MI=wvpXjU7$Jp&ck50TAZ1H^PspZzc@^E z@u^)}F491YX^!yQmgluIxX;@^cnPTBj=}+9|1weu)6RK>@x5T%>4$#JvSr-RV%`nN zFo2|Cck1lGDhoqs6u*co%54iyKzQwZge-%TRVj=I<9?^*mZ#JsM*ZG#Z0iJ#A`D!3 zL5EPv6kAwF5rC&B(e+nrFa_+i%u%Mw-|t|?05S=5KZCHxG1ay*>njdF0D#@U`Y6cg zVlG;!m6bq)VTP;F#Z22%5R46*md7-xFVN~;&5tF;(3)-R!R5D$T<(RC6Sf%;F7v#J z)}ReuTHX2m!ySo$sL?ap$IW<;Mv5fo|H(_!aa|k|y6rm)zmV_5U-tJC8pKV#8+#TL zOCaqjcm3#7)QT(!w0kgcWVPAI3~p@?3Te*y}TWPld8{Jz~Plh9A z_H3g7}sayDV8>&A!9FCs0*$`N= zK!AL^p}SeAwYDey@#LnM8k5xd{gJE@VEScv(yGsar zs|j`}cBu2%BN2NHVM#h8)y$PDF z&ShNjo<0TYdRlHNQXCw8t~&PaIql+$asEZ!tJ&0oM=8qjz%>_2kuTvn&4(GO-b71+ z7IU-3(Alu;B9bkCj|CT>UrqW>hUU*u039FcUkH$JQFHlU9B8lD#HA~6bxF|)frqVgRsfgm z>!=Nz#Zh>ltv|mOJ3%J*oPC-t+!UYLyI9xrD)zLtg>m_vSDy?r7>9rNOV`}jqR2_< zh&=0+t+KZ@Zx!da#(xs6kCL!~2@bS5JdM2$-#zT`V!hs`gI(M4A{`Cv4z8Tra_ImU z4z1;7+o3vc=)!2Gu(=wtl2UuOyoT7debkB7J+gmdw#Y7RvVqL5Hpcntx4n zMGLEd(w4zfN@o2bV%&7>OeSUj={OKfL_J!N6$QHOwshUu>kKdr57-JPc|~3Uh#kr= zaGVpDPDoonzj+M>zjsMsvcarw7iUZC;_5u35Ky6tJ`2&LD5_NIFxYkOdIWS`FwhFt z@37wUU_miyN(U253MAaB1}-*SqT;S1Pbw;VGUIt79QKHNZ$})dYs{D7HWmWA!F@9q zOKxfeU7e)+L)9gqrw@3@KA{9(KP93OEr2AUiewF_hGm4={-sU@gLf{r$DpV#r9rAz zHS8NP@5SW%2eX}Cl`CK(Tof!er@x*aWxSrCy93(^VNt^RW=6EoFXA{g5SRP$Q>%jE zThzqe{L(A+3+cL)sThq-Sn4~Tbf$Rn%{AxF``YPMl_9qu+-{1K zb7FnFrxxt2dOKpwGSI)sVj>v~J262W!~N z-|z-%A`@zkU{5-%-mi>jfY7}Q_{m>iVuKeLLO`;9W%xTd2>MM9Eu<3JY1o7l(q8dh zxA$J0)1yggAqKvG2Yst6y&+*-zEVtC)bhA40ZiwL-k^o3teX5cji#;}G3B7G$%a8a zJQPsxvlsC`^(B(eh&=SYBN$TD3m`RXKw>UH*JRoLwqf5rl@2HNt~gCJsk% z&pp52^YVY5d&gV6d&9ad>mUf);4Wl*;9LVXc)Tzz$vkXAaUF-7ao9|tgu!UBSYCwnIDuoh9wYQR!a^DJ6pq8o z4+5ge!4TzRT+6Y5WB7qP3|r?}oYvFVvs5j^ z%fbOZ=#nK7UhFR=tP$cNIyU{{2xQjMB2nVu^4gQ~=VIUbSJskfT zmW&BZU|L)meW0u?4<7~_BZJl0RYG=ywUWF=e&>KTl<4g0*9JQ}I{W*zmP3d8fSfon zpq-B&?`l5OrVX9{u;X|t^=+c_WK&D)z`)>Wa!k{PMw7{@+qcj4Yw^U1?(W{tFJDfj zQYX7lC6i;PKR!1(nd%!D?1*>96J2w2bF;Iv3kwVL^Yi!eUjGe(p2&7Hc7H5Y*5*Du zg0Iioh-outkMIX3d&d4A-Vgm@K7|(Qym{NY%BG&oDZVqEQ?ak8V7kQHvzvjhO;i`= zPBi5ntvFg=<(RS>UYff9)T3M1??$k{#=ppZC z@Mma^;nnBX-f!8Fyi+OU{e18v%3XFQr)dTqdOrHo`mcYT-qBn>^Ry9hHQ#E>JyZAn h#m`D!xPJ3db|qAY8Y|u`KfCzHb32QfK1b!je*hp!1a$xa literal 0 HcmV?d00001 diff --git a/auth/auth-gui/theme/onap/LF_Collab_header_gray.png b/auth/auth-gui/theme/onap/LF_Collab_header_gray.png new file mode 100644 index 0000000000000000000000000000000000000000..43781fad95932ca2989a58916e5db945e2a345fb GIT binary patch literal 21018 zcmbTdc|4Tw+dr&*6Caf%p(s8m+a${vB0|~15H(bo3E77WV=0Q%P)HgXOV&n>3Sq{Q z6k)QD$#NO8(_DivGM4A+zQ6bVJb(ONzdxS&gITU~xsLNZj`KL)@AnmNZE3Q9@6o*i z0s{NZOpR;=1a=I<@1=Hcga2;%ecBTKCyqD1insN};(?n1?g9pGzPH?un|a^Fx!btk zbPM%wcGndU*oO76yNbVRVXouq>#cnA?={LH-hOav0Rdh85WkzQUheqgx7=|aJ}4P3 zy-w!1hZ{=9LBm4T!ta9nZ4cA10C(FkOFP#vFIR0h8GXIux*pt6v@X{ok)uWRCyWC3r8C%zsbns)hCO3%&vF$2F8y&$z0dQ$2o8O<4_bR#Q{+ z^l^1nHB}W=brm)BGisVT2z4D*)#Lwp$-tupxM6i{j4u9XEcg>j<~APhr=y|*0Dv-p zQ1%VLsiq!d!TE8hacX<*XQ`(9&g_A4Z@>j z;F%XoJ#M`+4zti|XUL9x`>gTRv z;~wZ66yOT42Uhlf8pF2xzYp~HLU=YhRskOHqTIY=5+t$n{5P#Fh)%}0Q^?=9yPg{fkYg?TQ0q!^Pz5#Z=zIXm- z2Uy?s#rp={_Vqh{!B*qA#Z6ZapTD2~F3*48t&w|xN3grw#QA_Y^DNFM&snqxH z%f5bX>|rv;CME|4hhpx>CO>;#RYlJ)Eb3*kGP7Q}e90~USox!`kIfzdhuHlCgQcbA zZJnJB4PS=X?9ZPYevXZ|GQQ{L7vNjo)YR6!E`F2vBxz)HtgE|+^5#uN1+Av0rmekW z5CluhK9-eNeCTU!WiY;c`5GG+UpDZa*ikVuGWzb_yT?T0_wQ{vukyaPwKEvsX>__k zk>@b{+xYm)4D#d0kH0oH<>lwUdGofty`#CMbzo$)qN+-O8r<})`3;qt(N$MSp}fk? z{Z#+CvFTfV!At?c;o;$*KYxyn zj{f-Zqo=25WMpJ|dWOaNF*!NKX0xYeW_o&genM~#c+{F~!wtr@3 zc6@TOxV}Yz;>BhU_w~cC0eW?HHuE#Hmo+prB;a}f&F9wco*veZzLAlibUK~c+uPm4 zWU*MqZ>fWWgRCDva(Wxa#>S>+XPM02w{NNK9i6Nn{ngdgtp0(YV`Bq@gAd~$zkOTM z-QC?k0CseAeXOV&AD^hL`}F1wwYRr-Y+`~vJPZyEwYPUt-+iFds|CzF1_lOae*Jp# zG=gedq&dD7e9UFkZ1&7|3mi6@X!c!1PpP!xm)z!_sdoPAe&KVyc2SHFiI6=UL z5R(1w{rl4ThOYuQ!kJ7~4WldlW4%D(Z6N2}@Xyia<`zQ4U4d*&eSg=rhU~Y@Z-t!= zZ+aRz9L}#_znCG?@d5&u^~{V6>_Ym($@?BSe5&LfuxUi{;Fr>hAikHFmsc_PSV?H1f!D{5q}aa2R@XmKy_yE4H{ z)#7x-;4(Fc#jWU#;%@4#RGoCZv)qTvLZpzm8)WwCI?G3dpSvQw@mSyH&cc?pZE-6* zpFGz04+%32jm7IIv<>h2v+>jH0PgYRABD%ZxDuz(=@zBDgoQmenax=*$(E08zr5`F z)jYmwSHAFT8M0XB6|_0rA&if3g4bGJzx?$+)iw$ncUu2F*jBUrB^^b(S%y;dGGX1> zjE&(ezuCX*J&5{B!JCJEv2^10yWxs}o13eXULTt%mh#ZmP){(v2BsKRg?DdxtYG=fv_Odrro}7oh>4&1S1RQT*Zhj~ISo)Q6I? z-fq_>7E~wA2iU#?9DV6nU*?OO!5{iXpY+)d@Ii0ioaM!T2(OoWPkgM4s6)TzxVREL z3x{wjOdn=qR%QEgh1Ib;d})&E5rW*}@C&oc97iR2(Dw;7qimq9YK_PYZmY?XjtR5W zM>Y%vHvX6=>{=>yFeyikI?Yd2zWo?ALzgaFf3n$maCuNuS<)w{gf&|+a>TBWA2SjH z3E!zx*7GRl++==rP$@$_{^(maD(36*a8`zW$NLGM+Cj{FU!@TCznr)(^@ji zJ*OI$X~M#oTLVg#*KXmQ1NyfGk3D+t+fS0N^dxzgh|?HS31MM&$adi;7_7^*@RORR zwvUkaFX^@5G!BmwwCi~vDNX8=_;aB$?_x~wNeV}Mp9wY7i?AKNbbkxbpWAe;oFnf) zw&zK3U#U+RBs5SvU5&i6X;FCQ-K2Ba(a1__6rl#?$!zoMx(R;V%-bgEyrbNwDeG*< z@|1$gtxW|Sle2yuCHBM_B{sk&59AaDAsYbwyXyn`HwI|yGQ~@el|Puw3hVtiQ55`f zwOQV^j&&vX>XR~89W3UC{A^{&n-Bfhig{5x2iBYVHF$9tP>dCW4$(!;f1EP zufLM)4yAI^R!yvUk0v+fJwAf*6mpuM1iCOIfumU$@kSD{Hjq_{xK@s+UgK17I=!WJ z7|VC~9q5%h-UYG#qyg)o6@BO1E`#TK-)^o15ioZK=B4R^P2s=P`G)iN3BWdqymQsrL>4zqgLvvZ}f}iI-hqca#ER{^z1%MaHUT)Un}0!Kh;!BOriZupW{}ZOzPvSe?E_AE&DtTahDIN znx1nwzxY~z+jL>{YOB?kT(2t$&_%s+Pn_2)I!d!sav+<&zJ_|@wRKwgrOD|E*(>!+ zJM#Ej2e#4nP5JPJBmMHpfh{~%|MD|{IKQxVZCGbYS?4Ez#pX?aF4BxgzGg7xdhVy< z;%EEfVHzh2cVuYb0x*gS&k(&{(zPCM1mrHvW!;^<2)O^aX5s)oIL^7;C z5jrrQ4ufZ$n}d-4{BBF0M)t;rh9NCw9(l*gTjt@Ao_|(Ni1+6k$gU$#OcLhngIw2q zbi*27M9X(d%b*6nxq&!ZG<-klfk5LLoN+yN<8b=-FbwlN6a)BT8)!&off;zy;#Nzt=!h5}}sJ2S#n~S{t2d+D) zOEEJEUFX#|jOSkBHK{REZq<>%dDIm3B5=$DU$M?}zW{_GOY|RW7}P*EvUFLWcn;kV)`U6GooR^3UU^?KkeSdHGD^D(g;4#$#LWXAE1b}d zrq6xX#*T}Y+`7(N{|Iuuer%&X?u^Kg)SikGmH~I&n{5mUYAp80d|E*p00&S>nMBrM z1<_*Dc(!2io+mcwPA5bCJxkF~#p#!)o%N1a87X^YxENeokbjVM*|XWXQp-|_Tf7o( z9eFINrM&nVG~QimCI0on&f_z&VMBPWrPYyag(*vp^01ES9u8HMQ@e5eBTM?U9UWh~ zlSMz@z4}|Jo}jqm;|ER&4Y8g$X6Jwg0O9TCyus5AsSXTx3mDWgR~|eush_CHUu#P7 z6tnAyxJK^=DX)VSSF#i;g_xGGaeJWSt9$?2+a&8qbjbs}Ll-7)^UKEp2f>}KF%U|l zOOg-d_D1Rz?Bw{gAGi(t8=_t-D)Z_hjkPRXUxApa-F6h5QqCq&#%S9|H7%}sy0jGR z;l)4)g9qkY+waR55VuY9K3GPu?DWd$+gVHd)g$MZth)$T zg5LXsTHbr5uCrsk3~vK7E1ZU+VSlF6qHtqKF7nWypH@k{qKiEAQKlU|UO{%fp+1PY z%h~{#lS0P|?&xF*V%!MV%h^pd=m%l@-b~^y)+sfq^x7sg|K4$(a=MzH!b<5SX6;d8 z8k5?ugs)J#n;vX}dNLpnB+WnOm`<*`MEKOy#7Q6PwV=|YxjVVScc-%H{_DmI8>g+0 zQ7{S6jX%Ka(dM9{VC3eq@ZI%n`a^{fzQxKj51i%A2+m zXIAy1wQL!pQAS3^Y4?&RlH)g`za*P2ec>!O%)4KCw#I0=_M`{UCHZN3 zdukfpvoJa?SaYb<$Iq%!bj=`4qX(k)=L~Zu>HFIA5wh9HHB#!UoPNi0ODbSkF9A9p z1UZ71JVIciL}QhF@;TE8+{J9rSOq0cP)7X`>WbJlwQ(*oJJQ+{ws{^v zb8T11F3AkA&*{h1w*tG~b&>j@rES)0ushLssbwoc;w`oV+WsNge}WsqejY5LB>vsRNR+V%Yw5^?!qU6I==opPWQ(`LY#4Pa>5_4fB!1_TRVr`%Ioi zs#IxGjfIal1dWF@|4~VuO>_&cov=##wavJcnc{Mytl#Y4I-A>oNFl$aq23_?H3)>L z&k)7J)br@;hop=i=#O5H3*KcgLLad5WXS>8B9N0&0M=jmH^h@?Qy&8@x=qn@Bcrqj zc_VW;A~c7K9Zi|5h_>Qr!m4B5^35vJ%bgA1eC zalE=zh+x%0-W#d;P;X)qk3G-p7j>|%XYZ%RK>b2HteDCpj8FbnaAGppbTpBUnib)J zIq{!SLB1nVGf;aNArSD>8Xrp_4YIFrKKeZm{_`Z|__q&+ zaoHc$SZUc9v-mhASQvNlm9ku?SZ9QE#7R4TgNgD9mP2K*JSc5lQov$6U)b@)VbGtZ z5R$`}$~3q01PbXM0HFfSu9%-6`b`=#||Z ziA$ASbkoTm&UZZ=wDwgDu%?f8Zn%O#Az~YK63-6*Zf%{hVNQmS5x{<)WTv2ECc$h4 zvAh#gjvPh06b5g$wi~pEOZW(u(GNlVa=ZsMU!oLqogTAj$FZB6b34x~8U1F&8*Bdd zSp{<#uR<2rrHMEr$>KS|VqM@N-Ad&mJI zrYi_z2T>pM9MJd@2dbre3)eFz#{IB!=oi6F?K+aYw^NjlNVxUxDWS$E9#(kYy67h# zf5z?K5JZV{DTmvLYR=P@#XS2I!E_Sx4aKhXIF>;&Jc*TDmNuH}J}?X(>_k@bIm z#3C-xN~7VBWz!K6)d7awxh_mo3J2yDpJY8dRDF8^9BKZPmBSTkWbaE5vXTozi%FXa zXX0J(C+(2pB|Xp-rJoQRoOWaFX+Ob-m>FD@P~!JlKXwI141=y*@M9YQMRVEwEn(_WnVs+m zev*G(+u#(-46lVSWMeSp4W#$0;##T_WN5Gek-KlRM_f2zXtlJ1;I+kn8qv|JUC#*3cakV3Hem`Da&dNvZ~7%u&%Lozk#ws1Wjej+5Pgocvpsyt zd;zC;{R7#(_4sdp#r^$jm$u)vroZ$Qj@qdwc>US9ZCba#FU}#gS$qY8Bh*q4+PkC+ zRYtH20M|*d*%yuk)TH!BAjl-?D$hc$58lK#NDBnC5C%MvCqW$%4q@t<8TABYpqB*YhW z7{20K?X7PiUmLWeN{Dho+m+CPPEA(|vE>A7oOfVO3GEQ3Jw6J~C%|iiKu9}s;QORR z)SsDSc}?bKIq7HBF#XNyQ=q>_9$k%GMOZHvfErwi3}Q5qU^Dl#jTlHKiI3KFV$K7) zX|;q`NWB9D4F06vNeM7#p-FiUuCdCpu_5jr99cDKF7(D}ICehdBlt!Ayc1`((Ju7G zKzrGk4yzzGd2g)}fE})+^Yw-;krN8)ks4FV>r?d2KY@003`PeWwv$Mt2cw&NiL4Z% zf!Q`9s$vc-#=|=ls!W-mDiqpXW62pBA*$HX)tsNASl zxC=B}H3HnQ)|xiurNw(W&L?pnBNaS=3Aaj%Ce$I_P-%QzsgEe3)dFoL0~Q z&E0(Sne<1qGn;Uk`Ml$Uc>f`5k2W*xE2POCW@y@_qXkBVMaK?Yct&B{-u|t7F=gCs z;gu*SYIk=29}bRe|Gk0i`0v@v6JHc`5f^Y5?QQCJffn_-J_mx)4S-b}BQ_5d4#M`3 z#r<)y5dG2+I)7Ao$@P<@q7c%nJIkV-k$ zV03bts(^?&NFM_W@kaRDY1&6fk;rWC@MCtJ1MMpTZBgXL~9ldS?C*ast_PMxf zv57iNdVcTY5Mli#)cnv3z@Dfn-utT1=;Xg`Mq{r`jRNWj>gH{yFI}HJN9-^b(`$XN0jFVx*^IZt>p6y4})p zr(_O-Nu=qg&qy~9+vv(xk+0(dcGlAQh>!bexiYfa|M-||A#$HF&hps)4@2+dR z?nZ_^tbHodB8ik_+V&LcfifTD=^uEe0oZSmt5DGm-7*3zPWbT{k%q|imE*t$ z7F|1!gVTa3ip}>Zl9?G6Thz})AfV>4{s`H4OWaP;M1mG#^fO7#e-1U5iGGzeGi@p# z=7{+&0lFOYZkAEX7dvC&_>~fO;ydNzt#UVqc=ZQYW4m6ySw4`NKcqZfM>%(DuDn?@ zxj@kTRDKFU&v9Et9{nu;a;nk=sh`^)PQgiwLx<$Ru#UJdC1NpP-smJ*oCPI4-vW*d z;8jH&yCgRla@Z3NJ4e6%hSF)2eaX?noFOx-f|R|H_}jekUle7(zo+~ZwAcCK9b@&# zLbajNrx$t80I^lbkO`q1{8>f-bTdLboRH&LW9VfL{+L88*sJXLh3gKy&?R7iH8HyVSKB*GWdeevTB;WiE7T#pNVha_LE; ztIR@E&TzsaD=XcGYYAYnGG}C+;ZRcOZnM72<`_wQ$>`*|xDGT!A-55yH?omb0Uj~p zZu~b<1K>6g9_HW3tvoEr=2L@cbr(2^W9CT@pN)0hg%hLbDH&@2>){xverb#`yi!#8)#XgKf$I*?oIx1evZWp)LMhj*>}${Akj1 z@lU762EQ3b&(}sIIk2GStb2%<;_af59cllh}0onpHa^J8K5wrO$iMjf z!dOUr7j^+1n368b`76_!QPJx?R*Uf);CIdb zKXn4s_V?>r3lkE&AEiDU(VpzZx|sA$kuo~EI<5is{vf6$?CL_x60pBIzCRaMY~C88 zY%^S0arq=%&E!@%!I{e2F#Vw2Kcw-SX?wx>Kz0mJF6wBiL6dNaBN{lX2cf4Ki`z!C zB9CsE&vth#@(IIDVr|4c4GV_h$2hK@Rych0UT#PcDLK#&@5trDhdZ)zJkxgcK>PHb zFc=f<4f&zE>WH_CZjo=CM=G-};R>>FC*Bt(lkP>UAP@{X0ozzkKV$~H@d#j(`!PkM zwsFid$Lvhz_U&nZ#q$@!zg25g|X{RbC+p2B3wbROC?+_ZvIveUxeh`Ds4^C?nZpeC{u8w$JamgxngLvmbFwiIg`YIkslBin? zl9Oo;=>P+hY;+LTb4d@!bP5dKx5U>X4_j!l`mSMCQ2#ES!efch@@*v;e-LXXJ&NAs zjb2k1%imK(I;otZq{vp-(0b_Yx=)zAPUa4t3J_D;%>0fy+O*cz;#)9XmbSL%BjAvM zd;G0z;2nRtuiNgOnDFR!&+&8BTLvmF<9<)2MOJ-fx2SNWD;6F+(!4*}-`S02CvL0L zwpi(^=ob&37ff8&uG!D;j$OKDQgO3X?2zx`LhBum#jk0|T(u|ceNwsy*xU8P7NXK; zzBX3RQ~M{&*Ox9qpR%5J2GbhHIty}eXNSCaWb+yrP+bAIf}AOuzm%1$%GIcnoR$ja z)U4F}9-r?>nhJSwLdky&S8vCIJsb%}*>#{4Rt)J4B=KmMMzWI5=admArXSX5kQDl` zmT<|a(TO=#7|T^w;ojyk1Z`^hpCY?370XW-v*}MEb>e!Dsgd)Rnj!AqfBA)3%Cj5m zoa^1&Be=6KY_PHMrgkn(Ul>FWpvRiy{65`mq?V45g&3v~;|Msyys9A@dE%pVTyP;m zcIes;aJoI?63w;z86WY-iP`CpGW7tiF&hsi{fswlr>Be$p;J2xhI7EzTnyc1M@?iq zx&vyZZUy5$`9JZ*vy6DsLf7N+kc!86(U1aH=v4{wA8qk@hM?}s)$h-eAxD{H^jR9k z4{Hh_FX&UTGbYT)6dX1KGH?4tQhUxbd9}0rYPS(bhz&~ZXV=L7L1e-y+(`SO*8l(~ z{#J>|Y2`(*#<1zht3;gB#8*d#VONSlfSf;hgRz>M=p;;&{y3z!pB@dAkTGa0qh8cL zM=ivw?_TIr-OvcbbX{eH4txgER^yVMPlroFg!Kj{72cw|qGyY?O;;jE`>q)ep)yF` z=B;-wQ!r)bM$uDQ^PDWT$F}I#XlWFKr;U$KDuxE zfp0@Ac=v5c{mN*2sz+UXR2_cXh)UU`{DV=<#F*Y`{3MPB2Y1g9B~y?E}Ztkw0tibCH=S6YPN)qxjx zOq@gg-jaulb2-gaR#1cHQ3U_j!dyHmf#kA&$F-ovK_Y=9+n(WJa@E3uT zGF<1Z3{tp8%Bp8UT$iVuRn6rEH>v1gfQH~EG6WZC0J>s-V^UpQ9^DI&jIE{%J!S}s z>Xsuj#B&Ks%fHxGQL#%sk{L#yG%PX`F&P736>1Dh)|=W8a67&LErJhf2{7xhabX4FwpLrg(gs~M4*rJV?e2%YUVhnX z2Cl8)<3BIDDTx#eR}WihF{^f*gQSeA$V0ktrM49Y`5t=#s?NDWd83xJtgSe?W4to^ z@&?>LpW;qTqr^xDlHLiT&e-D7q>LQCUdy_;?rgNjD|kUyA~Gn z;k2Yy3bFg-ci9!UN^ZJ4wg&{{WMmO3AD;TLjhll!0o%DTn$ijyW=FCKms-zmx&HF- zKWIVkhqupc2>tLK89g;<;Ih}(0h-<_@H&F<&T$)5H}t`)^{o2ZGJQ?WfgQOuZM?1^ zfE``Bj%9Hp#hup9E$}N=ztf@5SL#00U9W2O{@MoxR7On#y0eEjb;2ZM&HiYAXevrn zxdp=psdSye(DyGj+rNhAvUtlH6W?!heORp$HDo1DjtREkvKvZ~@cwOYSkF6mF_+#K z;`?@wn@*EVwy=JU6KPz=Ye8BZ0`+`pZl(f z3X>@-2veHoTeSO7g!u|I(~rs!AEhCre%1YhK^ITue1>xb zD#&v(cEZY}AP%~|^)!FkX~Zi_SCA8#`bi)~09HFUh|lqb+{8)eyBtE}Ewon`w1~5I z@3UToE-2N~C8sItag8CJL4ho_Grto(Ne_uk^PK*Ox1Q-H)^alCe%M1K@#GD&Wn1m| zVFfDo6^sL-8#^NE{CaoiaD7UA`oZ|jHF3K|+xCIbDbE5UUTccKGcZgELH;-O(4!2dEj(L0)qD-Q#9b z%FW)SfQnt~FFfjgy4IOVi+t=*eBb1|J3`3EYTvbsDQ7N>C&-T8(VEdTB*>dfIO_(F zXj2FO>@oPZA~9$jHqFFDKCD>`i3tktOnZr)5bN~%d`z$+?%Gj8IQv^;XH9~(H59yt zlNhx~%rawRCNw9G`5lSu;4S7rNO0#~aZr<*lmO<$FUW zAm&H@*fmb@>gMnL1Nyb|&KyP~Ludl@&O!m}zf&a4jS}xL-mv4HJv0j*E?HjG55l@m zh`j(xUUy>}BBGvqp`*?o3&duw6aI-%TqlXN1@)3Is21Ls+bi9?WZ^)LcL65nGYjm$ChXZf0A55y!JwkiY7;6rNhKO0mW6kSFuZ4)yC%uT7G@#a6c}uj7 zxSLL)f)5~ir(~Af&UVQ+YM0F`?a?wz@ZND(OTCMCn9n1ei$AW7D7K(09Y{LbMqEY; zHxc*HTgtI^m2hAWN4b7QpB{r@cH*(RXS%OYu?yOWzWd@!^Zxa%y@vE%EM{?M1mYMkMH82@`vBM%N|J&?N*@7 zhhLJK0hKa>{F*ptZE_o2whl}&?(AbnP#ppysH!5bA-WRlY`(&++FPlPre@vPwt1?e z9g;;!hJ*C$Y&r*k8Na9(d4ix<_=F&74s0^{SWs z%Bl42;l{pq-*0r4J*((D05vN=728-TuH3DaZLAK5%3inD;lNMae>oiKy3fWVv4cnZ zQ>#hr&!Lm$vV!SRXND$73AwiP@(PjQL-(tcfX`%?JHD4mr;5!GUyTcq8YEYu>z*MR(VHZ>CF*9 zA%BEzBK6y(2Wsz135D&RIYo));o*$#HgCV1Zh!_?aQYzw4uA?vwXZNK`YFAX-WF}d zrePFTn)VhZK>#r~>@OT%b6GfMv`um0NHP@06NQ@3zsB{GiE+Wc4i0l8jFppH+en>G z<}V!;&0Fv5kFNJb&u19@vo{mNJjyy-HEIbnDn0{w{OHyf53BF!%Zp?jB^Czb9D-!J z)ty;zYhX}T`vPv~p~(zVS-M9~qu|yt@GFa=sJOWLL)30Ae%7rTMwL1wM|!#&fF{A{ zJn$eG#2$>uxO7)T0JZ3*%XMZvJROjfA!DzDn0oi2I6WNr75b=_pg#tVE1Z;JqUlO2 zy;p|A>aJ7@+0iKLDZ6|JqIQB&Emy3U3p3CK?$qTV^KCk3FB=_JvM*J*m4sKBvW(hk z1k_0NM;xX~4AZ8rPJmhF7$(ew)q7QRN*0r-eMGbEyL9q1jD~CJx3%Ms>xy@N2HJl^ z)Zqpo?(%3YQs<2|2hYAzx0MP+e2w7U`}MZ=;o54GHF;j5PB#t1tg5w7Z4;anIs{8y zs0gm|jH9W~CfngTWb2P*X0haUf#lE=k2>IxvDs_;kj!5RF{Wo3uHtd{2vOeFX+bSrxkU#<;}wHhZt zJ9*7qjGhUHdyeoP@*PQicd5LjGoTRVAg3uO0nUDuzFzVtgEZufJ%KAbyP~!&6j-)B zHAQWY<<{zEh?hTdU54Qw+bQ~!Bgun65N;>2VwBzAS%2LPP`f!X>W(e&!+JW(9Qa!^ z8v#=(nQ(~l07L*bw{|P*KAnG$t>iS&hxRUnb4|uZ@+@^&-cqpfauR7|3bwQ_^__E>CQ*XicIg7$|NdXIg@Z! z)+YIHUVJb~Pf~qK+1N?$6z)85EM>|vEw(>`#L5Hxv0V|P)1qw20YA7tu58(l5Y4Hk_6t#eb9mXifTufg&;7;!aQ&3*bzcRZb( zA^m(!+$`Rd1qBx4C!LsgG;CWKCt;q6&;|XF+Si0SvT5E?bKwUXZBa|_#As#__KU7n zk*|JV{Cf7LoW;v|@$Iz*)5*7k$_n#0WhuT7T>B-S(36K9^5P zWKMSEr{6ohz_|}6in)%o$Ga-u?euMkBAuxV_K=JPe$_@eZEvZloUHZg_w^oidEmK* z)C`$TvEPs4^_A2fx-E2Vr^%kOHOw5-B^?f{Ul0#eY9HLM(@>UKyL6-V%dX^B30&B& zK5ucekAhNJ;v;FQqXdaS?AFF_^mbpydve^9I}Fxx+hKj5f~j`73;iX!A`bE8Y)^(S zk?q%ET4MkHQqW#q7?gDV!)~ikVti{HfAPH2J!^X+6jE{zDz#fbJRd}$N)H9_#0#`75qjqNPwO8fpRi?&&>wq|T>{FPsfU5$~ z<#!olyXBz^GB$9#oogZ3f+>pUNtu1PozDD8z9U_~ zMmyRWFpL_u<@(V8NeDTESno^=YLpc*i;^otRu1iF3em2;MY77T7pEf;Z6V_)wnrtV)$ASbvxbhsTgTpN%_pO?wzUF4}Tknf`?vg zyD#Ay=`c9s#}l$L`V6rC29F>`(Y4VL`ly2-zK}0uHKF$_6t^oe^tK=BJJ4S6F!XR2 zF5cJyy}&ew84c2WHT?+4oK}9oO_U`=7hvA-1dN6a2tTLuEtwEe6XxzDMoB=4Xo`&O z5P8512EVl9&%=y{9Vhegp)Vc=Lr}`skWixQv0zzu^evG7`+; zPSaIrnsx-IZo4-&n4kEjd9imgT4j!%_maisWD=mC{g_?0 ze-(#Z6V{)_d*2K%b)qdod8RdDB=G=pEz$v@hR8MGsWIqJZptLr($%CM)uj%UJP1}9 zbS+Do)<#XuX$J+9bwxH-v&&r!fYdp^WuFE z#F9dv#L-fMx%ORTVu|a4`Ztyeg%3qjcF**I$m-%2MJkvCz(C&W>$s70n0(_!&u$7v z75r9$BmDgJrbBIl+#wMNS*3UUh}902KPcUnG9nT&MWHIni5#k7a^1bs4}cfSQ|6mV zo#-=;%W7Gamrt(tTspi^xRyJTXWCN3Mu$OiFU@#;2a*o+e_LF6VmM^~#r?|;)W>B0 z206`nY4nxSECwxgb!;&7Q05#Rb1fLWcsK6M=w!T@l@q9PyrQx0cw1A2h8{A&s&y?^ zb#GtOzjHb$*r_6{+oxYDDEA&?eWLH^%$GY zQs<)FeC6umhGxciwPDz6*W|h1%l@4C*VUzXX73Q4(jHI?<3_89Ti4}B{Ut*(9KUtK zcp+2SQ}lYBaNTKN&Zm%~xSg*297##VDn!b604JkvAz;s?T*MX>HZlY=Q>UB*X#>bm zK|IbE)?pSab)cCiMi{DR4z`*5!713M6%#r0qI`bvjW)r6B%acwh$^?XznqXRBezc- z2kRhEB7K)QiJToHFttLvi!U*t%Qt3O{}npH5*MUtUBrRujfS(vL=1X9(z65QjK=HoMXTP@}1w0@E6g-AL_0 zpFtB^=(|R>jfuZ^OL6vcglK6La+RqA2ck=WKr#g6Ddr4s5+!?ctzlBjIYQZ#OKd-o zlx%Q<<2`GG(@2yXh=31(_M!!UOlz|8bi^Bp->%)B*6 znv=&LB4PhIbnx!u^kV?7y2R!?nbZ&tQjCVkHE3A+3De<{=(5@FK+?nTD=*9W0&TKK z&Pz|cI?H!>Tn(om?hZjCtS&|LNf}IelM@=i9vGdj+y}xctQ+Bv?RTBIbPin+CYyLR z>39sm20Aq;JNBvvigow5sdJ5zta>%DHG|J7 z`FX(KVWjJF&S0)M{~EVpsP?Ov+KHsVYdT+?L#j&-r+d7tJw072NB_!6MfsF2w!Lg} z#g%>kJ#O~9(aY(}*}&K`;6hv70<&>#sPUM&KyRqGi|Tld2PLUi?T?YGx645Mi+#g5 zP=Lnu2={`MmmTc&zQ)e}CS&v8g=|O7N&s&$@xFi+5p}Iqtu^U+ecrdj)To6$pWr|O zpMyJD_i)fb{JW=SNoM7q_ZH*e4hXv$>VXj{LN+X*kR5AA=I5!cGS_L0TykO3V= zZKM;U)6J&~xV2g^1si!Ff`>j3h;VHMr9#aUWL=TP?&Yy{Z#lXi2Q)$nyFnr{SpylbW$Awj1`kI zX7Ox;d3(1L5Bf1qRq3x&G3Y{m-V}uvTqj$Gta4V}pjXR%8GC0#j~h)ia$B_3`2Ntm z1}=Wqc2HK%MF6TpZ7EZU#b01o3f)=t%?FD;=MqTeBghBZh@IrU8@c3UIfh#x_H)FO zKM;d1kGt5FA?}jz1n|hkr0Oti0b&q_vtTY1!f!5L|2KeJ*cIWjn|8SivQkF`-dn+t z&hreC)e+{OimgPhjsI@Ab)dfT*4LSLJ?PXidWp=a!?AhlrN?$Y;a94}ZO{w{Ujql7 z-}GSbzFV6SXx|_1#?Ih}2OvWtm_yrQVll8Z>k_#16m^4OS1=M%+k4h+u-oXKgD-iV z?qFLO*jl#{)_V31zt1S@u`FlDob*|@iXV}+Ylo$76lTP#2;jzEMlJ!RzT|ENgQ zgDsTq6lg~r+4HHyC)|ZC7#Tsh(eR6;78mt|J$i7LTX@z_cHpbg8!r(dF3jnycTu(K z>y5SZ{fVL51AW$J$4B|w@oYrxx{<3kWhS%M*PJ_>GM=mXjaaKxc(>A}^3NsYfSAt) zlJG#uH&f3ff3z)eC^mSlLb6YD-M79?$+ya$kQ%oGIS#3`*Q?)+Ykfe*1l{omGBDCql1g?-J{{DUKmIVmZ;>qnS6 zdLh$D99!3DXFR+ZuoHuhADVeoh=|&W*K7>@FqVTs+jpRtW>zCjji44DKCI5BOEsQK36J~XPmm{ zQ*oueXeN;lxnpC|;Ti{Fk&4K4o8UCHEy!W6b!bR_gz+Lc4ptI1xJ2P4?f8K|AnlUE zWIzSGdC?)2Z09gnsd435|{o2 z0*nH|jN2;sBpC`6`}&BP2VTa>VK;Y;^yumJ=XG+F?~tr(~;U=1qs7sViV* zuICB_E`kR5Ntzmrf$3A5PDWQM*=le3!5umQ*Ku=TzG++0^M1?+s%IAjgLTNwLYLF( z2uom8hdZKnd@6BB(X?(pMc*_On2%Jnz1#tQj_YE z+n*=RoZ%}1G2gS^T1487Q)B#n_h9u@Ua zc_LQ9&sZnZM5R;$J)>Ds-e>iLyi)JHxz_(vO3D~3Cr1x_ek5{X=+^p;N-l$O`ia^0 zPIST;5r-`rwxBmi_Fv{jaE~%}Ip6Pr^|Y%(hpJ-{Dcun+s8ccze#0aNX(XH%QEo`@ zCUwe)D8zMP5VV1Ib~hD#ziY4aVyzJn0D`=ub_4^U@2tmXIhc21e;K0ON65nZ(^~uT z&;tewxT)r6@!yJmV$kYCid9h1eEz|`G+3@Hk5E{HmC1#Ky6{I=85^hIEVs%&wU#hs z71YRgVj43TA^C_4Y*^gXA-M*<3XYoeZfBgQmliAjWvJgwo^hX%)EW8>6^BH=F&fYM3Q(o94#OQUa8g!OXc4nCL^C_wUpcoR2zBYurpEjnHo~Ltey<_^9V(NgK zo9m!(m4KbkY>%$SX?g|5{b`>4q>jC>@F_0h#Y#uj!mICxZAFLr92^G8vezonLthjm z6ywV&_DBP~{d%8W$+we+^xV&9PJj>aX~A!>$xFL(UL-)3{I1`U#EBakj!op1r;gHB zxee<5&Gp8hIs^0DtrN!jBQyWJsi9oRWPgfD=My8 zJVZTbm<-jg$Y<~}&cOg+&!^UM2}LO5Wjg`h3!E}jZ&8(nt1+#SxFV4B0)L@$*os2_D8=_e6rs*$b~!d*0^ zUsfWEbKli24b`1WC;cH=PY#gyPW0V&-oD%8Ha zN($mzhp4MRBTB=Ee_Zq|IoAez5hQh5&qb{@k?rQli*7TW*O=j3Rmm*oKXN9*aCe1yH zv!%m}Z`F1mF-m0BC>8ZPXo0VP^`Rq@0ml@gK4Zpjc{>5B4zVs=Ro-@bStMloJa~f zOVw5hM!9PIuve3SrV43d+N)y4WDhuz)fz27w_BTZblO>B*DF?IDjuMAlVH>VL>5ix z2gRDU7zZr-)~0)0ar*xMbZ{>IOz(dj*G+dl6gjJdA{L4Gk_tIx%4H~8a#I-^cGi*dE*a_If>EpEn+U=?XPX z1PiRPLAZ-<0Q}XTsOWzpt-QFm;V?uD+45y}AQy>5a;68^Iar%g`TfcKLG4iu#=19H zVH-QS3$#>BvNY?v7{BP;^3gPG<-atOX(W#u<5%-O?CZZ8YkA|*f%1qOC|bJ~=~AuH zi!9UpZ}b|>)=3kAv7I}dVAs5_O1wMHS|q{9h=i1-z48I`*k$ne>bIRl!h``pMN2Cj zMsyyMw*wm_kzee<+vjEvx-Z7aRaXn(zVqO$aN(#gB^>9|8ZN$D0R;07b?=AA`PT2d z@E4F+7beD8!5LjhvBRYif#k@zN+J;)BS|4~XiA?6bJ*4SSL)bbv(Ng}2q-K22mTpn zt|jF4e%E`Q#ioKsoY)k>*h1wRPENRkQf&IwWx5nKwLbXd78g z?w@Ly&I5A%4Wq5eW4((S zM^Jei+nCoko`SCIc$8s1uq+wwIYRmrJMIkU%oTQlPyap&Zog6zXfM}-MDH=H7Y|9S z3TXSV%BR5CH5O|_ISXZVOOH}0F17rd3rp>4ZC;DgjkybcY}_eg^O?(XrAa-%^89xe zPi2qbMx)JK3#qfZ%=_e`mKAf=2!-ly_7hX`5JWY7Ze)$?sA)UeGzu~y#&e5;+W{Sb zrfyL!1~~zFVH=uEeHco@^Y2!i5T`mk1H6PAEi7d&VHk?~r(`$MuTU*%(R5=j zyveKmieciJ0pen4JGg3FOw-<9VdV#T{n?uPAyy(7O#KGJIOgq)un95BVUa@$2GJJ$ zgztC%E3^&&^;oUJ=LNzbb=7MR3yrNv5ay*=_E3EZf62^ExYfe)EL7(a;#vI9x3wk^ znbb)GHS%HS*OHX+XLCotTBm~?i?{60aFRJ9NAA13+@DX!{UNbJ`?7%w1$6Z(1jw{x zcg%NkGIKrf!-?K?<3~f0-y|(UumiWDW*14ie;p5r>~Ij?w#?ZMY2~FWdr(b|4zp@$ z%_9m}o`~7wqkomOJ4o!cpM@d*G2zT>oPF}<>LvHo2vRtYy<%3g+E9wh38|mO_)%0{ z*!s!?ROSAD7$5>Nbn(pWSzDG=>@{3zV4>juC41E;@bi0Qs6-uzp4p4C`A0r-(yjqG zw?QVp{sYxh)+-%Y2wNHY#3F0PGavD}K)SWO?zZsSkugn0o-go)*t<`Yjo*y*oeSXLiesb%Qac?-}&KBO+w#F{P3(uRZT~p#SO>u zZP2`uj+?!@FHUgas(mH*!(U%NgFf?I5qPKb%T6vyb2CRyE!jjU6#HAeylE%4>&my_ ze95`5BRlj!bMI9j!mL|dg1O_FbtAN-M+Dg{630X>S z2Gm`Dwmk>Znhdxe0siksMja+uRCodnA~4e?&79^H7m7*;)Fh3#W~HAQHFX9w!rMMhx;m41z^tLZ0>_j z(Ae~JeUhDD&FD-Dx-Ap^@QEL@I#skAK)*nm>aVZwHV$)QxM@WbP_2N8(;9NwT( z%q?K_2iI6@;9k5R65d=s;Nen>!DG`?@8)!(PZGR08xF9zjih~NjeEf5UDylMc%Fz| z-D-u&4XSxDMg`al)oiVI9c{ZwRf{-qi>@-5S|HDQW^mqSRLRM^n3D+&!s031MX+~g zMRwjk1u|oXMQp(0jNNC~XYcqi*ST_r=``nu*G zke%Oy)YA(F6S*9ePYX#Ub`4P5h=l{gWU7gs!0{M-)r?GfdR)Y&Q?Rm^-N4sq$YfH5 zX@?C+ck*gzR^yzHpyg06k`71&1JqpYk`88(PdpAl`aW~!YR1?ISH`+$LcEaa;rjGK_!`NRuA_ej1h{Y0Po2h#txHTT9|ec$cO^5N=6Qj^?#^D3 z!TOq-dm<>|B5Qae0zp(L0n~=CtL!kH$v=51FCJ|f)p^BKrpFPxa3ENj2@KwHE2<3; zb$aQ7Aoy$>-A&DE&SJDSY412G9FewU;<3?{;%;Vg)3Ri4yJ^FDJJ@MvQZ*>gL2f?4 zkH-%7(oLW9A0O%NA?%NW17Z5LO{I$UWxEE~h74?4`7($?f7|i*?8Ic2#LDe`d16X{)a$vWc<5VXh{>Flbl&}2nyJGeUFQ7 z2`Oc$wp*Xr)#s71b4j<4Ao*>*t`bCu z0QA~o{Oe9W2!5ryG^*F~t*8nS5DWdFXn4t*i~WISv5iYbbWK}z>maVnHJ2&m+K5%3 zVU+vUua+gO3aA&`rl5j#q2-Rfe- z>R`YNlH+w-0nZ86UMXijBOfQHI^f2jblk2u8A!-SKaYP>%qg(p?i{rEAjI49FQnD= z_}2@{$Lzrdw`U@ezzIk@*MSzX^^f|$T`o!i!+}@Ns0#_{Kp!tfhW4BPYGyR;ijtnT zH!v@CJSK0oTsIptVX3R-0(3!RZIds;P{q34Zf`ul?|c}DI=COxOSNC^Dd@XQnd0|X zHU&o$oinbC(KI@?{`I{+k5f}|XPwgu*7uo+cx%}_Y4`h|x5`o^w;hUqZ;h+9t5Da8 zqsVe05eDcQwJCS(LRn^EER=5nxY??}?vwexn@^W)%>62Ty+yxDDMpcY5VQ)`WF&~e zN12bFze_{IRvsAP8?|B;7BVqx+~3uHrO09bw^L}yrk;V81eF${QcYR}-IT?&jiYpT z5|Dd7JnUQFK51fa8Bi>SYNu*B`M@Cb=oi#i8^ZD+uyBLhoB{0dBBY+(W8S_`D!$Om z+K^RCy9{W?b=A(idiu-Zv|;aJPsX`sl?@sdF@j=X?u;Nh0dRlzonE4)8fLNc7+R$b z#fmw&c-3B{nBM1{{sxnr1AXfY`6f$#;(DKy5;|BD&L)#`AC75V2zX+a7K2+VhvOuWhGJFRa@}k5(I|V z_<+b~tMCwFTOZ~>CO84I%Cnc%s=Ok2)=B&RmY?O@!$%<3n7h~P_2-&HB6D;3Klk#d zvdReiO&~p)Mv=U+2e7I`fNiTS*NuWVuQ37-iIg-2kzF;Jo7TXC_qpwmt*$J3V}-= z2rL9MxqonV-ifzHb^%Osh%WmeBkz*ol^Fsj^WfBl*5kKssL3yO0?L5WT7BM;+*skf z7lKNAH~Q-qzbJIbP!QTDyN6v85%iRq(yWghs+fN7fXooB1*Z2Uchz3O_#a6k^}ba_ zgKIyRes)yMFXaHV;WwWS}50sJHqc~K%yU1CTv890gzdi%jE=YU9l}WmrwNs z_UvbG*gt<8n9-&1&*q#=t=YZZ##T)peqSr2CoIDkFNz1Sp0R{2%>qFE(2?PX3ZYd(7C?z67sOV&G zW@!Te0+NhO)qvDgSx4q?BPAj#1V>Cj_ChJus4NVnS8G5@5)_7JBC7baAO>zzq1hi+ z7e(2QE{Klv)Cl$G-%wCgBmKEC=us|dK%L)p&$V1{$Makc7t8lF-?Ps%PyzN3dSs&# z8<10o=l-7rpwZz&RERSsK_D2Y8wqn~QsVE73@9ML%a?+uKZ=(~hZ#lmHD zOvG}K0#QKI2o_MqxChf67ZzijG}Z8vaGfBOBg-&9E`K)cEzq!ulamvXdP~qB>dP)p ztnY|ScI4!lSL(bth#B8XhV&bq1{<9!M^x=kQ zi*CYrwEB!_r;(1|BDV{fyi$r=jAqeC9j5#vi#1^1g&8_8ysHk=Wgvb&NkJ4FX$+Dv zL7L$E?@2Z7H$?gA;67%{4e^@TGzW0`To8*R1HWMirfDUZbuo@7FdB-&97OR2_*I!O zvL}tEI?e=hCX!`iFpnpWz#*v42Vp!1Lx{dKGbtGe-NyaPDS6Ds39OF+;o}$Nh;7n$ z2Vo~q#{(l}6&R33-5DO>9J(yYc<9A@0h<9({a}Fsz$J=Hg7o8HL92OT_%8}f$Z&rI z;h2FC{`}GkGbf#p2)V(Agz3*mybUll)erDVfxIjHoQhC$YymyHTkv^}p}m3I$3=v1 z{Oe!oljcCGL+k-V7nI-VOt@xK(fB*x25!X&hbaP65{?W4rPh&e3-Wo8WN!tbisUNJ z8}9z?SiwWwf`XTPi_iu6N)`n*%HMDnD6s&=2@b!C{__3Y0Ty!w9HGC*$OjW=ZS*k! z?+T9P^`Mur4Yt{DPK{gnwoM;?gm^Pq>5j6IVEtSIf|{M0o&x*k--m>P4V4=dPkinmz444DsG%W6gZKrEn{1fG>Zr==2Ied}%}Fx&0hHh5 z82%*HzpUZj(cVozLkqaWTeIT{eRQ)ri!{xIfjN_xq3x_OLuf9OF-F`=yghpA&37~% znQOJzytvaU|0X&Y2*Z!Tfq{YIU7N%uV9o~!pvfb9b{fcbe|pG0VKxcsS&csq>!CoD zf@r-|o&AVcdg=|t5_>S+0R&JWMugbI!KRF8Pnig7m6+2&&i%rQVAB264e&M~Is@3sVe?3O!%$2THb@e~c(+192~ecy zQsT;qaH0{CiCp8vC16w{>_nT1R)-viluj@m5zQp-2@;YVcj&J%#*}C)qQ4YjU2xCi z-irTP@N$FC2$mOvpBlS>cLLW6KNmipQavzxfnJIl6#8QJr!d)0V>S(KF_ELkmKvUA zU}lG-nH*`NsYkO7Q274(H|*7*z=>3T0JjBSx2DJoe6qK6>*+z&3%wh>c3^&E{X)`> z@hx3|^Z?xorT`Mnn3y1xAw)@>g5ri0hd4XvULJjuCrN6BLKkUwvn@kzhHQ=^6PX?9 zI-ET0wvS>=5GlGyww}~2wLr>F6|X9~A-N&JEp$%kn#fO0MT14fMGa0_te{Skoy<3}U`p?a?n&lJ(GlsBx+Qj1UZFxuwUgo@O%5OefR?5?r8(u_ z$!lq?i>`}!1~m$L2Hrs&flgwi5K#FSSt;69$ex>4rE~^$W_u-hg}=p#7i-ObSWq?d zZop`>U9w&hT^7UW0cv1mLaUh#N`*`HOGS=asI^vfR}5UMtOBh%&WTp4tN5%;*ifSf*KZ ztv$9HHY4l~O-LEFtz8CB$wZ?6&W)Sd80Hu~VE@Aj$Cin0!)e2Q&eqH#%|Ojs&g5k* z&FIW7%dTUyWx8ZzVUA|aHc>ZmTg$PzvYX{Fu=m^f2o5b3OBz9rhKR;U<4&WU0-3^| zdRJ$qF{nOMS5sfBjaXWQN`4D zQQ`LG_Ugvw7C&kgAB(BO*=lt0&(Z8ad9)Va-ET|78{^&PJ@@Gumlbyq7X~j2cZYj} z(+QUbx1MJqCn)!rhmE_(vDNjM%igi~QrJDxMQeX?|88VuM(slT-^QicaoV~1ncI}! z65nXg@@Ej_07<_|uSC-rg@VQ$?_6-6zvsFq!1MCai)qJ+*ZyPnR-s$2dwplKhsPI_ zzmk8`hub&ScfD7wH~v%hv)!-jBkx`3-TdwP-XG79fDoP&`6lpeB4>&hD*`+W3>~r+ z!V-)O%ofHA(*`*QNf%`cXCIlF=g^drh?UpH^^`6RIC`kc>@ln(bmkWiiu|v5*j>~w z&Ovfv+y&G~@i4Kv$Zi4vK3R-a1jItkDcb^qF|A42*av?gCy|-(NQn7w_}|XPb7Kn! zWh0ld-UI}Qeav6_L25y)g=9)>j!wp|`{5=1C5zuUd0sYI=d4f7B9$S_CCfdPpcfWyXk84ksp^@l zQ$|j!&iam@?baRJy!QH7*Pfm3URrO_aMv+xSld1Zeq4PL{irs`-4k##TUoC}G~Cwi ztA=jMZhCRb@>a7-g<*^`9^`9`?q+sfTh(Xy_Vf$%w20EHX6Gs>&=Tk-_7=I8{+pz$j;Ic)wyS&6 z>nWG*sVTUa$QoyRw8pZIUi<2?+vtownmy84Q(2W+bGM85GvB^ob5Iovn*EY(rwXRJ ztah$JU;WXL+0|hZy_>dC3!x*^>bFDw$IaV&{OOH4y6O&Z81I!Q?^1Tl^GoB|pxXWH zl6w6S(B|NNlJ|$tylT6u`uY4?Pb+v;(z^3mZfC7kz`@_7R`2qO`?50$bT8nce`;6R zzsr;H!*Gh|S)?U=20;VAkbtUA;@o`Ynf(Tb8z&iOGd>K@*7DAZ`|kbEt~&<~hX(Ev zck3PJ(aZipFa?bKLoRCW1y`!$xztp1ns+%xUaz0oVCHJmUvq{WSbq1n?(bI=jBW;2 zgNJU9hotw?u&KKAfA#IUTzBD91QObMI{)fB^=xhKEv&5wcKy1C+76am`mImun(7RC zkz9*E%?4*S+sJp%yJvbn_vN2*Io$8BpLTT|@*VnK0yl#1!ru_8zW|^0o$_n5Ch;Hy zdY-t?FFPo+$r=h|3Xq-X0>ykZ{&o-DZ=na#$5(q-t?9}7Zav67=hswkDxY(cYwGm~ z-$&1DsXLK9diKNi5W8u;OTKOI_9uNhZ^m!p(s--R#5S7UtnTLQV?IS;R%-!Z_8 z{b3BN23fsf{yhR2ES!|a(d%~#z;M)AdGP(4+d%V4zy)ms*Wpr8O_{ogBc94}{r-bd z_u0C-z!jk!>*k#Iq(G1b+Oz=@FakhDg`@Al%M+HO;i5@bhZPZ}%Ai0K9u7CQ^gyN+ zphUsJpG?8Q2Gm6B|A27)3pr6HMcp8_j|oNa#KZgJ@9g6%9PC%CE9QR!2WSULEoUGg zbh7_^fu)p5Z+_wmV@p*{7fm@?ZWDW3dLvVNV*tH}t;3Ht5D>2i_fOLn;9^ARVQXXO z%Sk62Sqkx<0m2|&n3&q~io%nw6INXYACYR0WBD*ivi zf3En5EnHk2xEUDS-QDTkS?KMZ%o&)txVRV?nHiXw>3%fmoIUMaj6CSUjPAG=1z_O32`#KixZ=zl-|?I*y)^8d_a=lnm*`dJ{ue|i|0=ouOQ z*Y?j)-v3Cs)tmuNBKEen06Q0c6%!`_z|Psi-i7zShWtOB|1%*k!+*T^zr6bICI6T7 zXU+UDybS;Q|MA1vP4CbH0SN+0i3+KD0AK1sdY}SO@SzIbp?X4gysyQg2qiJ7f&xA@ z8lGV&*}=d|qF|z;T#yvce!6+2ETBuCA->=3INNovoZ7nF(_t@o74o_+F8u&*&)N27 zJDC%1IHV9*xQv{J4*h!p1Hi$cSWblAVSU&F*#EZ>1`;mNk{1dB5)K~ozvaO2m>^5Q zTQtzKoeyO2?CFceZV z>2Qt-?@$?&XMQThAalRkvcr*{tle}XVOF0750^5uDAA3N zNNmXPh>Va)co{~Ol9Y1W)Re^o45jDj>nBm9x1o;bsze=4k(9!oB;Sp|NVg!1m3Rd5 zCeh){IsLlbmXde7?C$C5Av2%NsmlyN(LVZ^fTTN|a3-N=W@lHQYQE4!nAe{eI8t6RX$W|r@l`e8 zMX#HFAd$(-K3AunL8m03xk_7{d!>q!O&TNB2eF1Lr(Mza^+==9=hX=bgP;BJ-} z%BajM%+dBFj|7iS%Q-_Pr%_RHc{$g0$4P$jLa_uihM+=m-?u&qf!|HxQuxTPEsw1^ z3H-COht@|{PSDArL2%ed*1xOP6B2g3QK)ppWYQ^!yHUN$J>qPZ^96w^R4VA%)621C zEbQcY&n{Jlu78C?OGLt-n4N~93isxR5Uon<`<}8~F6Nc|G6W2su6G%bkdW$hzg4GM zo#kVr6jBZ}>?T{6(gFX@fS`laGu4U{>O#aOl6=bnuU}2drJ_b>%3~VZ>Qu!(bD2Xl z&X_fgYa|kJJX2w+~dV2mpw~M z!5EEBN39@Se6ih?oJ8ZEr9EiHdG@Hvqk?+eb<)`%$T~boveZr>?qUfMj zt*xf-|H<}x@Vtv=P-=M>=c5c2GBP$1SDkKpT&UN$_X5m?;ij^$Mu?5WW<~03HkV|c z=ci3A9MOqrb2gr$>o)r(BXlI;-X52;x6zyiS z3(c|wvBJ>3-5QI63Xe$D>3jlD6tuJAax{syHHSx!HeHt|qHdi}xtGaeKGE%Y9}p1d z?D2w6#|R4?asQ`4=s4PCvbGmLPp55QCJQN(rQB(DbOoq>*Va zM>jswshz8+Uf<_dEMsU?X1CWj_ngDk1CgFLu^@x$`zo0-B#gJ>(EY5FcE?*fNtt&S z&iDRUPOH&0QV0D3^41dy8alDXdac9uTy!7V)FR=XQ}EJhXN$n}wGjYs&&#K7$ZoeK zStg%JT;I(rf4)*pq0cx`Rk)X7q2>6LQPbn0O)nZkU8cG8xPX}R9!x)#UmibBZ;>a( zxWp~Iv%^&)7L9&)wP`=~5-*UZ&1NO}^e(t<3N^#r$Kpi9xrM~O)pkNEqWI-}Q4|C> z3zN+2bJ|d&|JgRg;H{pKTpp7Mamz*^nD76AB-y`Om5hj3;>36wMa%iyV1eEw8Krhs0DQw-(kJG_`7Gwc zX+Hq0a-JQQC@1u{iU6nwlVLwl^`&`f@JZ01>GNx~aNuo0^7jnXy5|#fv+NkVQsx9h zR_Zaa+sopJOeR;%d);+=JEsNy{T4SvXPntw76~gj&Y?a$7#}v?hFhmd6^JS_o$KyfwU{lnB82gauFN6~ki6CzH;q>?IIrmDt4AMR(gAK7C^e`2kx z1cfd)+lK!1DbIKHLdDETqoSo#N`Tl)3MW}Fbppup7>{->0|FXhazRzU!U>M8>< zj?dy8A@metH=QL6R^K$+t_TYKHwd4d2q`(C2;3v^N@zL`tDp z+1W&mJW&U2!9#GB8kC@L7DU<#b@U?wnh5;nT+`*H9Bi6JHpo?2n0j`SNhBr@>wAMT zTl+k`4Wk&WyP>0F(}w~FR{gvTt*a| zH!~rjU@It-bwV~5kWr)KkhqlW_#e_dOOPg;b!KMo<7a93HEgiCiWtWd@t5~Xk*J1l zTr_ya`1=q02XB1%UUC7v`{dvOjf<+YGMy>Xe%F7iiO~5z#7pH0$x&!DS$=na6v*XI z@`Wt98veHTiDZ{HYXElqi3*7X-|6O-NBHl}u5Y+Gbo7w<*X1PPMC|i&IZFzu!cY87)qAzO_LA@q2ZOd}2#cSwVkbz48%k^TCELXtP1%AhiZ z+xW)jV-|-iv`WDPYbJhQQd)_vT({8af~*B-Mi=Asd1=^JuwHL0Eqk!Vid|Ug%gh64 zJpVj8Cmcw)nuHT32IspyS+a-Rv-_um?^N_Uc}YPb;Z=c{WhD#3ly3wLpb(T;dz&PA z_bezQviNOsr@rilMUP}z~a_AAdjL1?QNO9WH@#)N&(u>Cft5sDZg}KOc zgPdWJXX7dLH5j}v^mmc6tHq&;jUkZ3&`F1_o$0nfCNp2-vx#T0MSjCM<$y9(C^ozP zQ`g(00>OYpz>k5!s_}bhWpwO9@ANzzNYa)$eW1-{)UJnAID1A22T2pl=*azjp3YE6szPCCesw(LG;fg4aITx+ zolss=c7q86eG^))Wx>F%u1&>BsoDEw)i|BSr$Xgf(vk~#$$ghAERB##r-2Sq9DE3_ z-RqXS(dfNqH#1Ya+aMGMhZpsbbHvv6_X?KEG;2@GObN~%>0iCFg?_h(l6pZEobSAs ztY^B?Wr!4w%>-5Y8>3dS%^`{cVXs9Qa+`%UVr#}!0%VasMlLUzJb% zd}qvjY72(K#2w2RDeLTQQDbQWW%eVtzaVv4onB|BNxR#-;TC{XP{6A~0PKhcfg>5a zG^$fiQ#&p@TiB{)hB`H=a)?_76iSh=8T2;eigfh3H?{=R%UT$p#|`eU7Rxr*1MTiw z5}6E}bx7I7^VyO_6e?AbMJO24d0|2}QKQY7GM^kT;uW$JR-ycqC3y3(qktQbzP8{P0o)0J10#=~hPGMf;7F$JQmV1*C} zstF``FoRGAwt>Qhh43l7g9po9s_sgqp3ZZd*V)4XF4HF>VpSS7DkV{U|8~zZSZV8n zxoFlXlP)$ju!@#lJTCO$qIFu=WBI$sTFUzFx2VGa1WlR+j3HSz@8>JmC;^RsoQ;#N zq9b+MEz)Zam2eN2nQgV3N@Yn^B``BPi&R!ASzG~ptJ@~!8qMF{J)AEy*KcZ>ehz)KypFOUgCvLA zsyVv-1{TIJNl2W3B5>qo1~lnO_P&)(YeGhcr|PWJ0UJUBrm)=PLO_sQ!ajx6uWyro z()ClMBz9OE9W{p3**%d{&G@$w7BwMtra)YcYwb-HXEC!iIR$OnDl;aquz z`pWogbcfTwZpR>DeT}svwaa$DKBIQGB-_lgqrswWHe0u!py5CEqo3QY*XYk?Z6I#c zX0q6p@HCtQeg{6(V;^Edw%4szDCt$H*Pj0YSD)>SJ49=hJdjRm?N}_8nK+y=U+n(#zuR#8ODW?4J4;j*fFVeEl80h+0BBwwAEcu?8ZYj=S#y@eQ?NC&+ zc`JZW!T3{@whGK-M^L+Z!b!VN~B5L0Eb z-zNDxvN>L(mlX{B&yE~oG zQu7RwtjGxWMDijp9N>E?38x-h*vR0vELs(RJCZp|JfN;+n4q1|O(gp<7h_RCi>@D~ zT~cH>x>U%oH%S7O65%n7j;GiVBezbz1r_J<^gBJ0ykN*R0y>%u_2`lyCOw`?j*gdc&=RA<6h}*Vpyv9AjwRH+LSQ=T3a4-Z7q>AxR9t9%H(js zQy<_JeRVHZ5NV=v#Lbcj;_%a`-k&D{aPvq-;_g(u>h!`M;^#M9oQvsaxG*P%0RpoU z!_>l?=p=F{H2LjjQvmPWtWG^KByKAM^qF*> zyHiBbx~ybCR}3UwiAaMv`JWgm{yd2w1Z|=RL=0UJNn9_tN0*e)Izaz>Z_oST&uy0_ zAxE@cB<5TRRggxv|GtF@ep(BysY&)#v@%L0(_H&M-kv`8A;J6i;!lE3BH{`7VnrsQb#IIbfsY z(#Rpn)s!G0Z@9Ac8n+mbg_ULlh3eP={YUw6c!}4Bc4g$bA-{Qqx3C^X63?abeaRIB zK2uVL2hU)LVN_|Dv;yG?vsUfY3?z&)8PeO%|M4DykUtT?`IpfTHnk((_WAj}yRtb8 z=uIy>>ma&IHMOWyD>p|p+pekqu35JV9-nc$+^klop58P80UM2A?g$c!a}3}NxX>(a zMkIl>dHuw*W5Phc?Ul6TaGm5}b~#0)(ox4F40O62k2QR?VsPs!SKzKu)6QkYmJ!u1 zF@$Pdq8vhn9~gbg6`Qc21sZ%IZl0vHFk*$aF7>!D{j4)c#tMI$+9C-j9UkCKWu-wx z6&+@h$!oE!MPReE{kYvLM86vi&cLv|Ue4HUc{qr%KIOhCG94>NZ+t+suoRhNJG{O5 zJLF=1Wdt50MyUe`p(@#l{W;=J`4wzFDzX8|WO3NrwLu5@S6H4G{zM3%AI@3|C*mniQDK{?1B+j=K1of^Et99b>t0M6Ocs--;WX*1_E2Z#p1%Z zQbcirf3x?;#5o$@&L`1_jFebq|G_#%%4yd%Cd8!*2@VX9D_hr42sR5wfE4wa33a}^ zdYX~E#yDg|fKoG0D;Jlgap^l;?5?~_PsoTnzWJ@IUy?3a_ zu;hfO#I55el2z5}Xr8_FYo~W*x&CO|DeIq()8j(Qju-f9r`5SDf4JJ#NyW=^B1eY* zSDOxc*khXwSYKZP8sU_B)7(4|HTD2Nl*?@Bjx9b&YZ*Om0p50@&>-PuA z*B7w5KMQ=>5s+^}TVkdhiqLEs%+`a34q66RLVlAV=>oOan|R}*_}k*PVNiX z9EwbVagFmo&SP>S=@b&R)=PhqVff6p4hAej$@0TlVHm(jL!2@QYq#HOKFopCT}nMO z1IK+jk54;8v!N8D*i%_P&4TE8;|->4RFoqoOp|}hl_Zbzlap$+L>3W^(^k=;uR&&jmpg_54c0Qpu0wC9l!s=$T*OsbQCTV8}G}KVaWwEc| zl8ncFGQ39b^7~>%u__S4>U#W8L1-w$86(?hA0|x=+eEWKPY5wD0lgNLvf51siu$lW zRsu`$$>xqk6Uayzl!Y1xWFOK&qJO=eYS_&>y@bKsLiOX*k2Yr~ht;}FKcW3K+%22) zM>qwO@&A4Qz&&}53J}o!bb7rf!Qp4UJ~zD|LRo0-tcXpYpboU5GTh_T>+#&ucK^z?CUv4{%qyZro`990ndD=iJZPl<(NxTM##pCB%P@;$9FqCX zt1-ktI%U`bs!X<(xJ*!SbXzhpfdw&YVYO*p(Lr2SE~UX4(^>U6E;A@s+u`L^R4l`q zjVxmq<>38uE-)+>Te@Dq#|8uy_o)Bwh{p8(cqT3{?`XD|!FqkMv~x6<#+{x_DX>ob zN;e1gwGbM2Q3QIh1VctQbEL zwOA27g_JBJbrh*-P-i4P3bFDSB3g(d669nSsqlSFcMc`fS~4luY>&zDs4x}->mH>= z>V#Bg_fo@a2Bv@qH6#Q)HsvpDE6~D>V^J1#nk?OJhXt3@-nXqr0PM62h3ibE*gZPb zK~;VAulr~olEgs$z12FsuA@J{O^#>y6?b2^8nF?aNf~rsqPy>ByBgv7J^6-(A$xCF zHj7*wGg{?c9z2*6DyTRTyV;M^4ypFZI&Q-`71LFuKWs;6a}aZb&d(5i;wJf_-cU)O zB7aFGf?15cMja>Uis=cMWf@qG$_IFIhDtXSAGmT+#KJcsLt13{e)l|^KAbWk*O3TG zB1Rq0X0hq;f1C!xB}bZ*?Kspd)0@kF>#sHRB#a-uV&tiynVHv%kVE?4O(Zfq4wgU3 zx4iNUk^ewdncjRZ5siwd8FNK>WOQumfdLNIV&j=|DO4A` z!@?FZd5nyUhz&Dkn<&yDgmfri^@8R$)458%r}5Q2mG_`D^fcmyWh*56O0^q@=?TQn z#I+<+isoeyK+gzGoAqc8B0Sv-^{C7*%uj4n2SEf#ADY+6`#FJd-MRdKmJqHO?i2ps zUlhLYk1H#26nY=mecvFXnsQithD&>jx?KHIbLIKB`LX zobPKLEkEN-W34N^dRb!ag`+RB@9^zIxn91Vrre~)8 zCUN#&jHQN@l7`3q*B>OjsKA!oaN1MWWHrM+N0qR}nP(0vd!mi&qY9+g2~ zwlZ7l@bG7=Vx7CdL{4TfXw}vC1LT~Ol4tR_E`&bZ>iy6ljen1S+e|ql@s~?$ffXxQ zt(GOFUs4hZ3J7(|0UkNFxLiJ}Qse!lBvu;W`Sm$Z{k zs1bG@(jH2kPmv!@@_km zFvK_WW`L~(?DPV=O7mxR2?_)V_m}W5GZdh4_R3 zqk{d-tp5S8dYD$(py-jC9^b`+8N}Q z67!u}AD%2>*TA@j+apTF;?T*}ESr()Q4k41&^zh$I>caT0I^Pw+oX&2E(!NP;3)Vv zbIFnYWq6X4JD^9q59&>~hn}5IHY?R?7*-iicjcP~uX>EqFuWtOQw}gM_bCqWIFtLf zhv$tJna8^~Q_#qPrcle=RBd#T2c_y*Zop_N!pXmkEGGyL z{L`HZBohZ=7E=dR5SV~IvhB+xL98~+*oxeGeBa&TFWF5n}}1aKKSR6r;OB>ZPFWBZ3rT`wbeK`Z?Tr=D*1B$9JIu z-1iaD2X7FOL(P$eEjf1_zQLsA1L_wEgF!R<1Amg16a7MGom_nC}sckpEy4^V*yChR1iC}fAMxPO73N{FRrn&lC?LQxMRfxts^B9k2~ zCSrKhKC1EA1SIOBrRGv!JgJe;1FL(lxi#7-x}XJ&qChFY+GM_z*1} z`95#6n*4IQAwQl;$H1!VRqS_y*C)m&W^AHrCwOB%Ff59Vl~n%-0P!yvLq6nef*p|n z0fzm>#Y8WLl-HJvX?~DNs^+cA`Ww=8+=5&;1mm+)Qa*n% zubsE}DfbnJqq^_=D_llcFo#QCqt*5A2l#rUXEaUM_?@l!^JHB>F(qv_hkf1o=eTZQ zWO|mx+9uGFqDt{RQCWCOOby?y(hU-GUv)V2?51R?ge@oZ0UJjjvonIqJ(CddfWR{i znGsT~%rbgw0v2z_y(B<Ta=m`$ZXuAz|ql>`Rsmw~0e6Bz6J)yJ0hdy-A;9HwLv2*yMO3@hCi4r7M}k?yP#A|~BgNA^xz@rA zRb1*8v1Gj48Fm6j`B9OF#p!4cF$nC5bd>QIL8F%DnG6;S>nv$ZCU(V2a*b{}R=5-K zlO(LtP>h0fm)87Z98XpTyHZF=4L*n_qrWaDTw z7RMDWVs(ZT!E*1RQe`m36Jq;7Fp*g7@Nan6e-IsmefMqHa=n2;s+pzLM2};JyH{yP zM1Nih7>E~h8WpPa@|K-Y_C1I)yF}ha5}yQn+vXWngH~~ppNw_T;;`aUIkOqmdrFB- z5>0;k*6dboq@|`M|2?RDZ78ZgOS3Et2?IhpWuhb0wN!vqe`0o7D3;b<)|Dou+w~5p zK?(omKLXVti>>zGF4sFV2WGyY6Ky|bIAqIV1TLLe$UzNRc#}QGR(+7E8D0%`+uTrC zXOwh5iHaZEBQp>L?)rP^69h$DTiB*5tjz3ic?+}46ShqInpeM4D`>0Xea?+0yXfzt zXiXZYnN`ul#PM`4o>mYc+cu+_#F!RiJbU28lfCGuG#prB9y=~xdER}U#IU4C&6DP! zY@5|-=0~n|X3t^Ent@o(4wBxflG&UV$TBTPVIyFQ+sJg*G6;v04F2{8sm;D5mj(2s zbr3Px*ZZ03^jN#aimUB5Mtf*Oy~F{jO}(q|ZiI8v$MYWABta&Hk_wGRJ>i_KO6I3V zC)5twJjol3yamxBGDgc3YJx7gSb0d+!xDtL@KACZ-WFvl6Jx_I6fwx>&?9+2k#+!j z1G+^8W)8QbfXKVcVw(E(KMZM-<|^0k%q&E7c*MKAKPE;dpbrhZO#BW+aL=zmI248m zc0QRIFsZ6nkWnl+(-^WOnc?YNT+v8@*fRN3OG0y$$7{r!#|RMya=H1BVx?NcT}xYF z%F_$*oOFU%#B};wC{19SAqL;ba@N(#2c|y^%RL9Gq0q)$o99jL zOu#j);jo>`nTjzP2x>o{Wz1$4gKgK@+xp(9F+Lzc(jqg@_N(aF@m4$}MARCG;@L>- z{%k6v_}H)gPWM>&GQfu1Hi1AL!79!2Pe#rs<|L;l3^*7Vr4%|Z;KxIF6?sDq(%9#a zSHLQ!Zn@FU0(COse1`I@R?t|El1(x;4R|64D@VQVjcrzb!4psOq^Lzbtw@;&^lXF1 z+ozq7Gk{>3T~E!KWk_i2b)j64UqZgg3!be_jsmnqX(Wl#*Yq((RzOna;%@+J;kl@v8Z*4)pw#l}UYiJ-Rd}c%3B)q>tkl*t0}aA|B7?mUq3cO5O+tM3gTC1cJI) z_lP3YYnRqXw3gqJv5Xz?21btXvz0Bnisj-Np@!o7mP)bK4n9~eX-C{LHF9~_NPoTdr47s*!HY-=kuH?D=;t!72()!wd-T^Oa5QQ*b|Bf`w z28TsI72esn9(lr|P3v);Qs1QDyn*#(ayo>9oOSu80<-#s$tdVPR;~V3x@lVLjrc4D znza($D0U~KUqIWDtw2-}&J;C&!>n?XaRoire@@<(q;f#m<2-a|8D?)(h7aO(D)A6< z>$HUn*)pRuzkz9=#ZsTH`anhLI)#2RM_;@Fh?-jH$LZYYLqemO`j{ObMfrk}ETd#y zTMWI6Rv6%giDJ)=zL=q!XFQeZfmTESXY)-nV!E9q@L!TqlkrGXkh%7muCLc_se;4d zSMB|L;^B4P@DNk^8VC+IJ)YK*u9)~MA~D_NaOQ56ZoO8sL#v{LY+9a!@aq|Kz{JnIvV#f; zC*!D_D4@H$i6+Y&`6D$?dO0P-rPo`}z|&mOnkr|lW&X1)ReEZ_r+n{tsm-+@fEZg% zsASOHLqPF8>*zY%QZpCy(`~!U9Ydh+vlFpQcCz>Qnr$+FB~I5R!3gDtuDby6iJjWl zNa8v9)aNo)$T2H@!=D;a`^jsEU$oM!tap2R4(IX>tXW1~_X5n4ZQNemv{k9-ob#`V zhIm#J7sc+N<2`YO5KD$Bq#inOkXv^R_U*+*Qk{))qms#GXODz3Bn~FYj=IV_$1zBF zI&?LiPSK*#y6Xez9c$5s)|1VJUqIgx#ygx( zT-jzGEZD499xR%8SRR`#V`H20s#x}rqh<0r9fhAqH8F;+gQMACWtX;mVUANd-dhuH zMK+|`!ct2F?Jfsy%Gh(CpjA|yG*d{4oA=xtGE7C>vJPd|$ZoA7wxVL!V)9%zUZ%0B zHM$F8&K3pvadw2bS86SuqOJRwXB#5zsYv~A`e)*-%kzx>)mEhmb?<-9C9Bu!P)$@s z7R*qi;^Wh2v)iY=cyte8NA^yc&16euG6Ps!_wuGZ46N2F>0GVW7E%k2-X8x+p9_vI z{3oR91Sju0mb2CBiRor3DD7V9E8X{A;wLrNg*G4rGX?=Ws-@u|(_z)8-7ptgKdpz3 zOd|a@l!Aev6fLJxzP88&>QQK_x?35KV?Hl@Q?AnlR%?tdQ{_8e29bLEXv?a- z_tM%+Tyw8F>Xnl*V=hTIn_@&)H|Q0K#nP z;r;61pi`+cAmLOw-Q7fBR>^gLER_?N%RX}&OOuu)&Htfvw_cu~MR0d|UE^6P(RFxu&QTGsh|F=UwKAYoSG(QmnmQQzNVHK2V6H9vDNsrf zH*~^iwB2ME%!H&4)wJK~j#PD12a|{RbOfdcE0}x_-WXSX*~flMQ>24pw%B=6z&x=n zAVs0qPu|ohR4e*O(F)PmSr=pSi zisQCi)Nhk9Q;e#lQzG@>n7keh67TeMCu4GQ@%VhSKW{~RKkxdb zS5#20tYKl4I1$G7voet}6D#-TzSYX+Fe0;_KKaM zg~oS-S~H*m(_Q{n?U$>mmmL}ky21h zJ@3vf^YtFjWXphBWN5{{Jzmp*!=C9#h=_;)ZV95BHkSF!y4AtSB_!@I)Ge|Ne7;J3 zp4Lf;Vsu~^D4tz3g0wcKis!2yOw**+1VR8#lpl%X=fskYba57`XV@Li0UP9l#LD!$ z31GuyWm%RgpLwnHO3vM^`|1W4>ze#NHL)(Xdo;_Y%kw+Fes}m$`F<>}RXMz#i)UIX z8ILEA_%o$0e<3m4@=%^l1(VN}KlvrbHoUHW>c+`F-ycOXN#|k&_#E~EaQR*Stlr>p z%l~@&VP?*!x(YmzWGgv^fV!`Ddn0L~;ALmR12vqxpcuUtr_>l<%N*nH)u6_r%6g;H zq$sn;iG)^Zs3^N7is^FbllnUm3wi~)bPy|(uf1D%k} z!KZTq za5$_Y9y``kuLPT|cBbk^LY1-0`AI>6w zVzDEDDu)5Xm}8~I3Fml;w1ihiQ2EkEiE`5g^0TTAjmKQ&w`e0M%t45=hH{JCjo^%8 zPhqVpoth>&yls5@WF5?#TC6%&bh8OhLhiwtd44K^|A$nOiE&Pyn)ZP(D52Tz<%%>l z31BA}QC&#Vi66B9Z@IgyJJz$hLt^zMeI=f0%Xm72Nx3`2Jo7}$NX#CW2=*6?60mQE zR;qN$O(MM>{vw-?9e1n!Ced&OW=R|tadt`Cu)O|Mu~>nu+qWvTb0lu*;FJ0?+3hH z`n^8{k!$ssB6EsNQ*J2WH#k09DnI(k7-y|s*G%%5$LK7nN8cP~I`m%ew8%if z;ZouybV^;;#Uj|IL!gz)zZ&1|{*`HTxMzZnYS4ebWCufQncRHg%Z@uo(Z&*2OdvF4 zfyTCVGaa1>bU?HsPZOM3KFqD9jD_u%KCcodltY^LSUoO(_JKYzk}rx58C4;5XAc% z@~FP=tJ9q^xp#q1loy;MSvxZ5Cps<5`u~bJ%ebhzehrg?bO=ay4Bg#=C=A^xozgip zh)8!0HFPNrN(qQ`H;8l$-8s~pdCvPj=X~AY_WrH4*WUO4y6%zTUb`Q9)ka$QbGAN5 zi-jQexPj%)pmqWz-2$X}flpMMp)6rT8LfwZ8|`YTWP+*EmnDWdYCFDBaLPKDamvbF z9eY=va;(+dq=w*`w%FM)SFqyD@f57ssJu)22xgWOwa5C7Z}TKQ)2v6c{s9w0BRR8ZO|3Fj3guGSWjj;Muj4jMhoMo;k3vxV?na;0t3Fc*ym3xO%9DXl)|F~S?sSX49y$x z`K8#|jr8EnMmNVRtX7)9@22hFQ+Pf|>)PUvZ2u7W_G=C;-1ra(M~)lTYYgW^PB{3w2db1 zs@plseUiBmJUa(rkA$AP>a_cN5YN5GLwz4eRCcZ+!njQ#Oh8yc(Q{v(Rt#nais_LC zm7S(j6ytZRkeCxzU^O}&^Y@jI5)t{evyJo0j?i5k8 z`6`AsV+ObB(jx)?&(F%%CEvYogSR{>`qya@Y+tFn!IyU?5 zN$%lG6z$)2@hbn3#FBPI3r3inyuTYfJw2gX|LXaC=6;gQr!K|pyws#u?F z$yQ4DLgRe@I%`iH*_k`dRiw9xDcs(F2xPj+Zk!vHo(EJZp6VHNg)% zsSSZE$c7#MkX*?Cl3)_&U>O8C0XM6l!)g)!%A($*Z%9kesBj~$e5LXN4Q;S3BaGoae}d zg2?~>mJY?%5#d{9FWt|-k=K-IXv3!MKFQ?}kdctM#?W{;Zvxp{pNtdggP~d4=k#MF z^c9~Xa3fO0*1N2*2dQO);dJgIBT8F}UlUz-S~n*v*kLqa2Mf}gkia;a|EvZ?YToVs zr6|=;UX?>s)Zn!mpGR-1@-PP%x#R_kn|7_OAz0cXs{%%CINBy>efIrW!mIR5OTc%_XvZ2y(9x@OH;-!Pl z5rGbeN+#Ert_xabv8J#P-Jrub?Emf^X3?a5l$qYrnQ}E1bJ>C;1^HW6NFYLSbBTCm zcfi>{EBxT)#H3o_T!WN-Ga&OryCIU5^gPnR(0k&&DA#N_MYE+ zS$l$++o3zr=xJj4MT)V*hltE>Npj^f~f+y~8 zbzbdX4|-nkQ2=zR2~Qm`BoEQCwlf?3gcne^5Kdr>V9q-^|1S-n>^>eAj_0Ktm07G~ z5D%pC>|>syL5iVc*?`OP>%>DO>@PCYjpZq->?=aPcy83YftOaCK@V5;Z7iU;?(Hl< zgwM$$AlR>4DUOPMLi!;N(a!ReBv_k3Iiu_E>&#Z005?_3eQ!+4=9-_&@1a2nvbDz; z%G3{{Q7^-K*xORKM)feUwYlOTYqBs{R>|N5a0V&-vQtAW;|vHHXA)1>orzIF)i0Dg zyOH&sM!_5buc$8XU#L&>#;(KMX_ohtx+`3sI@wD#2vDbi9N{2+(kggd|MjLKSb#Av zX`^Ta{VO?5uxqTA_9gU*ZmvpKn{?}as&r$v=0Q2SjLMji&`#~#R}wkPF^^>ISXK_1 zT&aK;^s-@P^z6~hm|BgwZ`>i9Y_VPnt^FQA1dlF<9-TMbV$}Q*^n)w7koPHIY)v-m z_6x*+Z*?ftWQm=d#cMpECq z$Y1i9O|x$GbySp2Rosu)`XI{N@}#_Jjb)R-mkI&RRk~@Ov|&m7gy_(v=EDe(ZLBq& zSE2=dSEPI&?!iLpZv$S{SJ?R;7T@AyC|7;a^c{2vHZHG;^Mx4pCAP%ab;X@^lke`( zV2Ghv!`_cIYuuCFp;T5)G*Bwhnn}B!v%_LtSY@mrWP9rGX(vZI2TU0WO*WM!eg<=N z&QA?CpqSlL^=cKJs2&4BV@$_MF)=BC5~}oTgEPB!hSUEyk+Sf#*szG{M#w!1`Q0o@ zvnV85qv(Qve`0RjV}El@m448n5VogtTBz=WGQ5S3!R7P{jgoDu#1ow7s=DgzoF41TdG_QgY&n-Tt$l&)CYk*_GOzn)7M8U*SYhbhfA}&YuCd z!a_OFRHwy{+dx}0I~Pvclhu_=#1Z`>5U@Lz_l2SS?+!Vps`NJOa##IFLH78MYs1#? zM9%D+I8KxADjC%)JR)z3OMRO8FP4e(N=T|=Dga5NIsK+fFYFZsI^kw6vi7##meami z!+d0t`uc9TvXyrjo53pv*Pir=z7 zT@DFWZu35Nycbzv^}U5QdHvx(@7m_6?YxhHS%@WOo_AdzrhjfD^_gI4i|pG+A(b~$ zGKea$i6!-g=o`^i?C>IsHunfQEzsFrYJd(Z`Sb+L>;3NZKLnwV-PJMh8jh|%kk6=^ zmcruV;(DMSOcCcxf&(yoGW?KUWP~7MT)`E1d95GQOt%tki{UqxQaX}GEu5O}y3~PA z@$tb6yZH|@d2s1Xw+wNf5(+++6&AK*49li12tA@NZhxlGc~xTVN_nKh-JcGb@3QG8h`3MUWBuyOYB})j3N#Gkjnz_#y966pkT@y4tgw zIy5_w2np>{r}9xb2U)T-tFr=mg@SHVFCn7m+J<){@}S4_fm0gaZS2pqBIdLqSA~H$ zu-yiVoHQlcpsSNo;P8YDG2eJF`6{@!^Kshi9c=k$Kw?^GpY{Ef!+t~#Ec!#xQ**c# z?5;TRq*Daib@{-$j$3Vlqrz#_6cs4p9W&=0+w+imzLh>EtkR~rbu?Sq_$^$qj*(L> z!$=&~>+TUxE8+7k?ls?Z!(ltTd}V1>>WKV9O8^ag$nPHjSIgOSq~f9|f>=&2b(Mzg zwBs%cNGStc5>(W*vp#iC+pNbf5{7Lk(T^C6e`=qy_4%`ZFQU!Qe8jY<4$K?e9IfKLd7wx znSl8pqKu(+L|Kv7qmu1Tr(+~M)YfzrFtXSYUSL>ICb91EzR5)XWo6&3}B?4B@%I3u1FSv z2W+6*5Zlb5ReiUh+=WQ^(m1JN*Pyy29PITiwGBUEI(4ZPJ6t7zfnDTxi*4mE+{>(6y?vQ66+}8OCdN@ z=hF1N3x)#!G}y!v;r%AkyT$J7?|-j`tzEve%mxHgOy=_zeF$R#Vj*Lt6cm_?`Rygy zcn-s_El`A5vr}Kl++?K?R#|?IL39w}&x z8%1;HZuQj~ogEFLSrFGl2`=hc&cyERcQf?0<&bRx=rFaY>U>{;SYEjLsx=C<=NQ4%0hS?Tl4_oqf4mZN^l}8B?wySmx;~h~0?gVK@Zoghs4b)758$7@y_db8hvTYqfdWW$bgHPsic$k z>Z=ja8i}-%;20uM=1Yjkd2=yO;EE8ib#xW8I0!6~8(lzCZg zRk#>2rS60;vUQG<+PH}=-!+W*&?8ZTQ@VB*F1B4u&ic06Y+(n{3M#6Fi-q%KN`+Yz zlTXMTb+^eDgh$(No;OU!+4mRYC-JZ#Gdx0q3!4w;!Q3jBtyX{M1>u*{(pQsjVqWfj zfn8eY-Yu5hq(gfo;FGTMGgG@Cg3-H-b&+r#OC;iL+dm3Sch%_@kgJEjjN93xqEARC zIn_sD>%m3&j0sWgwAZD#Z`qssyp|BkoIU)?6F;zR87-}ik=J#l?Z>*rv>jD9(}x~w zoA=QM)_6!JeLnl1hV>rIK$Ujn;Xjd+Y_5t)1Rxic)aH*oY;5nQ8fZcS&rE0hurUjH zENrb%@bs~OBlXr-T{{`gw(%5NnAzlEe2J^)nuH3To4qeV2;90_Sdn%)p7PgOkg(1P zwa}RGWIra89jwzc3 z#u+H?UbLf5{(OodBP!&45jG)lD)E)Ud9}f?()Xjo^k^O5rFuB5wG3>i<20i#QfVP0TR(1xSmD~d;X*xgn@*@w;% zG+~e8USDy>VIq_nL1g|A4NEDSn#dwx-uJwlK!oe4#X z_d32vdc3-vh*6K>i4#*rMxtY+ErYe*bS`wGs5-lggknksTxm4D=Wdymt|Zs{v~I1e zaNmk;Mc)+gT{K>{IQ$Lw}FW5-jch7N zZvF&lmo-^R)lmtE@P%+2V$JxAl?p-}YNQQR3>>1bMW|O~4Zm04hG2aj&l3ks%myHU zrZu2imuAD!rwOX$AJAUAxNg8bc_m1~QLlXd;ds^+In=SDMIYD!FfQYauqPP3W+l-8 zx1RBzE-d-3#gN!Y^_(0zxX#x!d&doWxJWh{c9Jg2O^O5yY?t-^+I4OnVq}2KvlW#A zm|#N>PyB(I38Mg&mq6l6h8{+w4luI9CLXz{TWC|iT0VA$8AD9MUN5sBcu-*^@7wB) z)Up4)ffgchesE8fKVG`xb)RZ_aqr&0{Mzw?;gNZnEAtGH+^=L`8^le4ii`FD%++k;a{3NY&Po)}2kM%l9wlyqHZ^2@^e4;v%T($xUsB$y7ETh~t z{MWVg_IEw5%bEYpL3Q`h*x!=GqZQxP43NxdCgPbQjq>xylMg?d1lxryS4=`K1s;Dv zdnYpySdt~N09v+*9B1GyCmwVc9AX!6GtuUY4mudb&df@)Z+`yxPFENSl^N6xOCKX z!XLB3TZCjL=5ILxyy-)-*;B3xzve02-~Eon*R>1=Vz*bnG?q}~LXcR(J*cNlu5m*J1Iz$c=ErJkmvB4A$1mJSsj&GDuKp3V(3h#u<)vn)9QgK`?|lvE6cFm{po^xb z>G?x(Hf7EKQWf-&=Sy@lS%JLIP0l|8p1>g`V=w9`_wFANS2 z#;P08Ysa}Ymn@SiGLEPzbi2FcioX5iK0IR=h+pbdwmq7zT@N(Ow>yM?SC zKQ4J;W0%|PDBm!n?rv*9y~HV|zTC9VFZ)YWiNw$_GWVnuAtvHiCY8kerDhMyrpo(x z&-*y?nDvK;THP{8ntG89tEHyxq!=o+GCrGFrDqD`9vSG7kR*gWc<7faA6uV^lL~vS z@lcPswb3$m$_jxE5j-P?t14s#E(egFo4!mlE#MB?aA0&Ej1;Zbm^&8%$K|0%g+o{R zV&S}|F1M+{e5<$R`N1!q7hNW;XRuP!(yYbs=-;ktyrE<3PZ8xFzr;tYg15Pa=^k(4 zq)2>JuwQiSg{DWmoKG2yO`w)Q*%MKDsayZJk_`WgJSG7F`E|+MtNEPJhYW`cmWqHH_1t!qJ_KB8!VrWcWoPdC)>p=G_VEz-^w=cg7-N7=n zWh~^j3be3>9gZ|N-WhkhKs=hqtc$?Bae z5*g@xMqP%z1yyM`393fas$Y}q>5G?u*Gs<3H4tB7n9irl5@GrFc$#K{Oa{}?!rT#7ghAal1jlR?$nZXZ*`LzsG92P%c{DYzfREyBDt6`&{)81riS7h4_<35S+EM`ZMhYYO}wH;($A*e!$>6+onR$#bW)I z-oRGgjPd4FBJ+9aaE^$THJ~v}f&SC`S|$Ioza`DG!o@)kPbGx>df;y9GU+7?3ka`8 zhb3vrhryI6DysX9FUnA+XIq*9dk{C=j)e))V3rlYp8Y4~Lr0}nt2?3z`4J=z_HnjV3N_IgTP;cMKE6jWXp*E#;PTQf@%+iURb zFUhR6*@c$+#TGdyp)fVz0Bp#ok}nvo)2*>59_d#o)N|){7ZRX{$50#(dl9+d$r(=} zr1Lnu)gRw1F03tM^)^u}e6f|>?gI;hSvV6miA#Y_Uz%7%&|$3-uQl5HHc^u@#b;GY_v0clkAbdk5;g6**L+Fg+VNE7ChDK z^1jc4gg)!^C1p>_?u^dk>xjoLHe>tu(tSbSBDr99uk`cPSG(e(g6Bb=Q1+H&I?2Qg zD5wpk^Rs%sg%Zw`<09`C&<)qz6oAix4|yWxGExo}NE01vGm(i|C;z_8c1eDKqEpu# zFnVtHn*n^|Vk^k8CGv0j%`18q>OuE_D(-5v^#6r`vLuL#z{(iY{-J-bofUX=6J+5Z y "; +} + +.response{ + font-style: italic; + font-size: 150%; +} + +#input_area { + margin-top: 10px; + clear: both; +} + +#command_field, #submit { + font-size: 125%; + background-color: #333333; + color: white; + font-family: "Lucida Console", Monaco, monospace; + -webkit-border-radius: 1em; + -moz-border-radius: 1em; + border-radius: 1em; +} + +#command_field { + width: 75%; + padding-left: 1em; +} + +#submit { + background-color: #7FB5C9; + padding: 0 5%; + float: right; +} + +/* + Options Menu Styling for Web Command +*/ +#options_link { + -webkit-border-radius: 0 0 20% 20%; + -moz-border-radius: 0 0 20% 20%; + border-radius: 0 0 20% 20%; + -webkit-transition: opacity 0.5s ease-in-out; + -moz-transition: opacity 0.5s ease-in-out; + -ms-transition: opacity 0.5s ease-in-out; + -o-transition: opacity 0.5s ease-in-out; + transition: opacity 0.5s ease-in-out; +} + +.closed { + opacity: 0.5; + filter: alpha(opacity=50); +} + +#options_link:hover, .open { + opacity: 1.0; + filter: alpha(opacity=100); +} + +#options_link, #options { + background: white; + position:absolute; + top:0; + right:2em; + padding:0.1em; +} + +#options > img { + cursor: pointer; + float: right; + padding: 0.2em; +} + +.selected { + border: 3px solid 2B6E9C; +} + +#options, #text_slider { + display:none; + padding:0.5em; + -webkit-border-radius: 0 0 0 10px; + -moz-border-radius: 0 0 0 10px; + border-radius: 0 0 0 10px; +} +#text_slider { + clear:both; +} + +/* + Button styling for changing text size +*/ +.change_font { + border-top: 1px solid #96d1f8; + background: #65a9d7; + background: -webkit-gradient(linear, left top, left bottom, from(#3e779d), to(#65a9d7)); + background: -webkit-linear-gradient(top, #3e779d, #65a9d7); + background: -moz-linear-gradient(top, #3e779d, #65a9d7); + background: -ms-linear-gradient(top, #3e779d, #65a9d7); + background: -o-linear-gradient(top, #3e779d, #65a9d7); + padding: 0 2px; + -webkit-border-radius: 50%; + -moz-border-radius: 50%; + border-radius: 50%; + -webkit-box-shadow: rgba(0,0,0,1) 0 1px 0; + -moz-box-shadow: rgba(0,0,0,1) 0 1px 0; + box-shadow: rgba(0,0,0,1) 0 1px 0; + text-shadow: rgba(0,0,0,.4) 0 1px 0; + color: white; + font-size: 14px; + font-family: monospace; + text-decoration: none; + vertical-align: middle; +} +.change_font:hover { + border-top-color: #28597a; + background: #28597a; + color: #ccc; +} + +/* + Text Size Slider styling +*/ + +input[type=range] { + -webkit-appearance: none; + width: 60%; + margin: 0; +} +input[type=range]:focus { + outline: none; +} +input[type=range]::-webkit-slider-runnable-track { + width: 100%; + height: 4px; + cursor: pointer; + box-shadow: 1px 1px 1px #000000, 0px 0px 1px #0d0d0d; + background: #3071a9; + border-radius: 0.6px; + border: 0.5px solid #010101; +} +input[type=range]::-webkit-slider-thumb { + box-shadow: 1px 1px 1px #000000, 0px 0px 1px #0d0d0d; + border: 1px solid #000000; + height: 16px; + width: 16px; + border-radius: 30px; + background: #efffff; + cursor: pointer; + -webkit-appearance: none; + margin-top: -7.15px; +} +input[type=range]:focus::-webkit-slider-runnable-track { + background: #367ebd; +} +input[type=range]::-moz-range-track { + width: 100%; + height: 2.7px; + cursor: pointer; + box-shadow: 1px 1px 1px #000000, 0px 0px 1px #0d0d0d; + background: #3071a9; + border-radius: 0.6px; + border: 0.5px solid #010101; +} +input[type=range]::-moz-range-thumb { + box-shadow: 1px 1px 1px #000000, 0px 0px 1px #0d0d0d; + border: 1px solid #000000; + height: 16px; + width: 16px; + border-radius: 30px; + background: #efffff; + cursor: pointer; +} +input[type=range]::-ms-track { + width: 100%; + height: 2.7px; + cursor: pointer; + background: transparent; + border-color: transparent; + color: transparent; +} +input[type=range]::-ms-fill-lower { + background: #2a6495; + border: 0.5px solid #010101; + border-radius: 1.2px; + box-shadow: 1px 1px 1px #000000, 0px 0px 1px #0d0d0d; +} +input[type=range]::-ms-fill-upper { + background: #3071a9; + border: 0.5px solid #010101; + border-radius: 1.2px; + box-shadow: 1px 1px 1px #000000, 0px 0px 1px #0d0d0d; +} +input[type=range]::-ms-thumb { + box-shadow: 1px 1px 1px #000000, 0px 0px 1px #0d0d0d; + border: 1px solid #000000; + height: 16px; + width: 16px; + border-radius: 30px; + background: #efffff; + cursor: pointer; + height: 2.7px; +} +input[type=range]:focus::-ms-fill-lower { + background: #3071a9; +} +input[type=range]:focus::-ms-fill-upper { + background: #367ebd; +} +.expired { + color: red; + background-color: pink; +} +.blank_line { + padding: 10px; +} +#filterByUser input { + display: inline; +} + +#PassChange p { + font-size: .9em; +} + +#passwordRules li { + font-size: .9em; +} diff --git a/auth/auth-gui/theme/onap/aaf5Desktop.css b/auth/auth-gui/theme/onap/aaf5Desktop.css new file mode 100644 index 00000000..affc5122 --- /dev/null +++ b/auth/auth-gui/theme/onap/aaf5Desktop.css @@ -0,0 +1,92 @@ +/* + Modifications for Desktop +*/ +body { + background-size:23em 4.7em; +} + + +#breadcrumbs a:visited, #breadcrumbs a:link { + transition: padding .5s; +} + +#breadcrumbs a:hover { + padding: 2px 2px 2px 30px; + transition: padding .5s; +} + +#breadcrumbs, #inner { + margin: 3px; + width: 77%; + float: left; + min-width:500px; + background-color: #FFFFFF; + +} + +#breadcrumbs li { + box-shadow: 3px 3px 2px #888888; +} + +#Pages { + margin: 20px; + filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#2B6E9C', endColorstr='#ffffff',GradientType=1 ); /*linear gradient for IE 6-9*/ +} + +#Pages a:visited, #Pages a:link { + padding: 3px 40px 3px 10px; + transition: padding .5s; + margin: 6px; + box-shadow: 3px 3px 2px #888888; +} + +#Pages a:hover { + padding: 4px 80px 4px 15px; + transition: box-shadow padding .5s; + box-shadow: 4px 4px 3px #888888; +} + + +#inner { + padding: 7px; + background: #FFFFFF; + overflow: hidden; +} + +div.std, form { + border: solid 2px #D0D0D0; + border-radius: 5px; + box-shadow: 10px 10px 5px #888888; +} + +div.detail { + border: solid 2px #C0C0C0; + border-radius: 14px; + box-shadow: 10px 10px 5px #888888; +} + +#nav { + display: inline-block; + position: absolute; + right: 2%; + left: 81%; +} + +#nav h2 { + color: #2B6E9C; + font-size: 1.2em; + font-family: Verdana,Arial,Helvetica,sans-serif; + font-style: italic; + font-weight: normal; + +} + +#nav ul { + font-style:italic; + font-size: .8em; + font-family: "Lucida Sans Unicode", "Lucida Grande", sans-serif; + color: #067ab4; + list-style-type: square; + margin: 0; + padding: 0; +} diff --git a/auth/auth-gui/theme/onap/aaf5iPhone.css b/auth/auth-gui/theme/onap/aaf5iPhone.css new file mode 100644 index 00000000..c356983b --- /dev/null +++ b/auth/auth-gui/theme/onap/aaf5iPhone.css @@ -0,0 +1,38 @@ +/* + Modifications for iPhone +*/ +body { + zoom: 210%; +} + +#breadcrumbs { + font-size: .9em; +} + + +div.std table { + margin: 0 0 20px 0; + zoom: 130% +} + + +div.stdform th { + font-size: 9px; +} + +#content input { + font-size: 1.3em; +} + + +#Pages a { + font-size: 1.3em; + width: 75%; + height:35px; +} + +#nav { + display: none; +} + + diff --git a/auth/auth-gui/theme/onap/comm.js b/auth/auth-gui/theme/onap/comm.js new file mode 100644 index 00000000..23309ef4 --- /dev/null +++ b/auth/auth-gui/theme/onap/comm.js @@ -0,0 +1,21 @@ +function http(meth, sURL, sInput, func) { + if (sInput != "") { + var http; + if (window.XMLHttpRequest) {// code for IE7+, Firefox, Chrome, Opera, Safari + http=new XMLHttpRequest(); + } else {// code for IE6, IE5 + http=new ActiveXObject('Microsoft.XMLHTTP'); + } + + http.onreadystatechange=function() { + if(http.readyState==4 && http.status == 200) { + func(http.responseText) + } + // Probably want Exception code too. + } + + http.open(meth,sURL,false); + http.setRequestHeader('Content-Type','text/plain;charset=UTF-8'); + http.send(sInput); + } +} \ No newline at end of file diff --git a/auth/auth-gui/theme/onap/common.js b/auth/auth-gui/theme/onap/common.js new file mode 100644 index 00000000..fbe8d083 --- /dev/null +++ b/auth/auth-gui/theme/onap/common.js @@ -0,0 +1,101 @@ +Object.defineProperty(Element.prototype, 'outerHeight', { + 'get': function(){ + var height = this.clientHeight; + height += getStyle(this,'marginTop'); + height += getStyle(this,'marginBottom'); + height += getStyle(this,'borderTopWidth'); + height += getStyle(this,'borderBottomWidth'); + return height; + } +}); + +if (document.addEventListener) { + document.addEventListener('DOMContentLoaded', function () { + var height = document.querySelector("#footer").outerHeight; + document.querySelector("#inner").setAttribute("style", + "margin-bottom:" + height.toString()+ "px"); + }); +} else { + window.attachEvent("onload", function () { + var height = document.querySelector("#footer").outerHeight; + document.querySelector("#inner").setAttribute("style", + "margin-bottom:" + height.toString()+ "px"); + }); +} + + + +function getStyle(el, prop) { + var result = el.currentStyle ? el.currentStyle[prop] : + document.defaultView.getComputedStyle(el,"")[prop]; + if (parseInt(result,10)) + return parseInt(result,10); + else + return 0; +} + +function divVisibility(divID) { + var element = document.querySelector("#"+divID); + if (element.style.display=="block") + element.style.display="none"; + else + element.style.display="block"; +} + +function datesURL(histPage) { + var validated=true; + var yearStart = document.querySelector('#yearStart').value; + var yearEnd = document.querySelector('#yearEnd').value; + var monthStart = document.querySelector('#monthStart').value; + var monthEnd = document.querySelector('#monthEnd').value; + if (monthStart.length == 1) monthStart = 0 + monthStart; + if (monthEnd.length == 1) monthEnd = 0 + monthEnd; + + validated &= validateYear(yearStart); + validated &= validateYear(yearEnd); + validated &= validateMonth(monthStart); + validated &= validateMonth(monthEnd); + + if (validated) window.location=histPage+"&dates="+yearStart+monthStart+"-"+yearEnd+monthEnd; + else alert("Please correct your date selections"); +} + +function userFilter(approvalPage) { + var user = document.querySelector('#userTextBox').value; + if (user != "") + window.location=approvalPage+"?user="+user; + else + window.location=approvalPage; +} + +function validateYear(year) { + var today = new Date(); + if (year >= 1900 && year <= today.getFullYear()) return true; + else return false; +} + +function validateMonth(month) { + if (month) return true; + else return false; +} + +function alterLink(breadcrumbToFind, newTarget) { + var breadcrumbs = document.querySelector("#breadcrumbs").getElementsByTagName("A"); + for (var i=0; i< breadcrumbs.length;i++) { + var breadcrumbHref = breadcrumbs[i].getAttribute('href'); + if (breadcrumbHref.indexOf(breadcrumbToFind)>-1) + breadcrumbs[i].setAttribute('href', newTarget); + } +} + +// clipBoardData object not cross-browser supported. Only IE it seems +function copyToClipboard(controlId) { + var control = document.getElementById(controlId); + if (control == null) { + alert("ERROR - control not found - " + controlId); + } else { + var controlValue = control.href; + window.clipboardData.setData("text/plain", controlValue); + alert("Copied text to clipboard : " + controlValue); + } +} diff --git a/auth/auth-gui/theme/onap/console.js b/auth/auth-gui/theme/onap/console.js new file mode 100644 index 00000000..dff87548 --- /dev/null +++ b/auth/auth-gui/theme/onap/console.js @@ -0,0 +1,272 @@ +function getCommand() { + if(typeof String.prototype.trim !== 'function') { + String.prototype.trim = function() { + return this.replace(/^\s+|\s+$/g, ''); + }; + } + + var cmds = []; + cmds = document.querySelector("#command_field").value.split(" "); + var cleanCmd = ""; + if (document.querySelector("#details_img").getAttribute("class") == "selected") + cleanCmd += "set details=true "; + for (var i = 0; i < cmds.length;i++) { + var trimmed = cmds[i].trim(); + if (trimmed != "") + cleanCmd += trimmed + " "; + } + + return cleanCmd.trim(); +} + +function moveCommandToDiv() { + + var textInput = document.querySelector("#command_field"); + var content = document.createTextNode(textInput.value); + var parContent = document.createElement("p"); + var consoleDiv = document.querySelector("#console_area"); + var commandCount = consoleDiv.querySelectorAll(".command").length; + parContent.setAttribute("class", "command"); + parContent.appendChild(content); + consoleDiv.appendChild(parContent); + + textInput.value = ""; +} + +function printResponse(response) { + var parContent = document.createElement("p"); + parContent.setAttribute("class", "response"); + var preTag = document.createElement("pre"); + parContent.appendChild(preTag); + var content = document.createTextNode(response); + preTag.appendChild(content); + var consoleDiv = document.querySelector("#console_area"); + consoleDiv.appendChild(parContent); + + consoleDiv.scrollTop = consoleDiv.scrollHeight; +} + +function clearHistory() { + var consoleDiv = document.querySelector("#console_area"); + var curr; + while (curr=consoleDiv.firstChild) { + consoleDiv.removeChild(curr); + } + document.querySelector("#command_field").value = ""; + currentCmd = 0; +} + +function buttonChangeFontSize(direction) { + var slider = document.querySelector("#text_size_slider"); + var currentSize = parseInt(slider.value); + var newSize; + if (direction == "inc") { + newSize = currentSize + 10; + } else { + newSize = currentSize - 10; + } + if (newSize > slider.max) newSize = parseInt(slider.max); + if (newSize < slider.min) newSize = parseInt(slider.min); + slider.value = newSize; + changeFontSize(newSize); +} + +function changeFontSize(size) { + var consoleDiv = document.querySelector("#console_area"); + consoleDiv.style.fontSize = size + "%"; +} + +function handleDivHiding(id, img) { + var options_link = document.querySelector("#options_link"); + var divHeight = toggleVisibility(document.querySelector("#"+id)); + + if (id == 'options') { + if (options_link.getAttribute("class") == "open") { + changeImg(document.querySelector("#options_img"), "../../theme/onap/options_down.png"); + options_link.setAttribute("class", "closed"); + } else { + changeImg(document.querySelector("#options_img"), "../../theme/onap/options_up.png"); + options_link.setAttribute("class", "open"); + } + moveToggleImg(options_link, divHeight); + } else { //id=text_slider + selectOption(img,divHeight); + } + +} + +function selectOption(img, divHeight) { + var options_link = document.querySelector("#options_link"); + var anySelected; + if (img.getAttribute("class") != "selected") { + anySelected = document.querySelectorAll(".selected").length>0; + if (anySelected == false) + divHeight += 4; + img.setAttribute("class", "selected"); + } else { + img.setAttribute("class", ""); + anySelected = document.querySelectorAll(".selected").length>0; + if (anySelected == false) + divHeight -= 4; + + } + + moveToggleImg(options_link, divHeight); +} + +function toggleVisibility(element) { + var divHeight; + if(element.style.display == 'block') { + divHeight = 0 - element.clientHeight; + element.style.display = 'none'; + } else { + element.style.display = 'block'; + divHeight = element.clientHeight; + } + return divHeight; +} + +function moveToggleImg(element, height) { + var curTop = (element.style.top == "" ? 0 : parseInt(element.style.top)); + element.style.top = curTop + height; +} + +function changeImg(img, loc) { + img.src = loc; +} + +var currentCmd = 0; +function keyPressed() { + document.querySelector("#command_field").onkeyup=function(e) { + if (!e) e = window.event; + var keyCode = e.which || e.keyCode; + if (keyCode == 38 || keyCode == 40 || keyCode == 13 || keyCode == 27) { + var cmdHistoryList = document.querySelectorAll(".command"); + switch (keyCode) { + case 13: + // press enter + + if (getCommand().toLowerCase()=="clear") { + clearHistory(); + } else { + currentCmd = cmdHistoryList.length + 1; + document.querySelector("#submit").click(); + } + break; + + case 27: + //press escape + currentCmd = cmdHistoryList.length; + document.querySelector("#command_field").value = ""; + break; + + case 38: + // press arrow up + if (currentCmd != 0) + currentCmd -= 1; + if (cmdHistoryList.length != 0) + document.querySelector("#command_field").value = cmdHistoryList[currentCmd].innerHTML; + break; + case 40: + // press arrow down + var cmdText = ""; + currentCmd = (currentCmd == cmdHistoryList.length) ? currentCmd : currentCmd + 1; + if (currentCmd < cmdHistoryList.length) + cmdText = cmdHistoryList[currentCmd].innerHTML; + + document.querySelector("#command_field").value = cmdText; + break; + } + } + } +} + +function saveToFile() { + var commands = document.querySelectorAll(".command"); + var responses = document.querySelectorAll(".response"); + var textToWrite = ""; + for (var i = 0; i < commands.length; i++) { + textToWrite += "> " + commands[i].innerHTML + "\r\n"; + textToWrite += prettyResponse(responses[i].firstChild.innerHTML); + } + + var ie = navigator.userAgent.match(/MSIE\s([\d.]+)/); + var ie11 = navigator.userAgent.match(/Trident\/7.0/) && navigator.userAgent.match(/rv:11/); + var ieVer=(ie ? ie[1] : (ie11 ? 11 : -1)); + +// if (ie && ieVer<10) { +// console.log("No blobs on IE ver<10"); +// return; +// } + + var textFileAsBlob = new Blob([textToWrite], {type:'text/plain'}); + var fileName = "AAFcommands.log"; + + if (ieVer >= 10) { +// window.navigator.msSaveBlob(textFileAsBlob, fileName); + window.navigator.msSaveOrOpenBlob(textFileAsBlob, fileName); + } else { + var downloadLink = document.createElement("a"); + downloadLink.download = fileName; + downloadLink.innerHTML = "Download File"; + if (window.webkitURL != null) { + // Chrome allows the link to be clicked + // without actually adding it to the DOM. + downloadLink.href = window.webkitURL.createObjectURL(textFileAsBlob); + } else { + // Firefox requires the link to be added to the DOM + // before it can be clicked. + downloadLink.href = window.URL.createObjectURL(textFileAsBlob); + downloadLink.onclick = destroyClickedElement; + downloadLink.style.display = "none"; + document.body.appendChild(downloadLink); + } + + downloadLink.click(); + } +} + +function prettyResponse(response) { + var lines = response.split('\n'); + var cleanResponse = ""; + for (var i=0; i < lines.length; i++) { + cleanResponse += lines[i] + "\r\n"; + } + cleanResponse = cleanResponse.replace(/(<)/g,"<").replace(/(>)/g,">"); + return cleanResponse; +} + +function destroyClickedElement(event){ + document.body.removeChild(event.target); +} + +function fakePlaceholder() { + document.querySelector("#command_field").setAttribute("value", "Type your AAFCLI commands here"); +} + +function maximizeConsole(img) { + var footer = document.querySelector("#footer"); + var console_area = document.querySelector("#console_area"); + var content = document.querySelector("#content"); + var input_area = document.querySelector("#input_area"); + var help_msg = document.querySelector("#help_msg"); + var console_space = document.documentElement.clientHeight; + console_space -= input_area.outerHeight; + console_space -= help_msg.outerHeight; + var height = getStyle(console_area,'paddingTop') + getStyle(console_area,'paddingBottom'); + console_space -= height; + + + if (content.getAttribute("class") != "maximized") { + content.setAttribute("class", "maximized"); + footer.style.display="none"; + console_area.style.resize="none"; + console_area.style.height=console_space.toString()+"px"; + } else { + content.removeAttribute("class"); + footer.style.display=""; + console_area.style.resize="vertical"; + console_area.style.height="300px"; + } + selectOption(img,0); +} diff --git a/auth/auth-gui/theme/onap/favicon.ico b/auth/auth-gui/theme/onap/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..3aea27221ca7732bc043a84f0cd2fcbfa3c80894 GIT binary patch literal 3638 zcmeHJXFycP7XB^~LWogf6kEiuV2nmIq-cVeL`~EXi6x3%5wRsgP_Y0mf?|QCH>Juh z9Tt{d$^r|7vXrH)TwFTRn>6X|&4Ru>U-BzI-mmxV-kmw;n|o%?+}ZP8fPx&9l`(-c z^1uqxTeN7>4paneiBFA~vLP}z1>z*wOieU@`57M{M~a;W5_y5}G6Y(xGQe^+f`n@d zS5qxiXL}<{lnasH9@Nygfp0zoQ2`I&X{`r`3(L{h-2ib02L>N?(b(DvIy(w+x94GWq#qS!MewvaiOMWjNd91>P7)43 z`|}Ws#mE+h!~eqDC@&H~9BGV#M0aGT^3X`fz}tE+vL5RoUla#{%TDC64nWBI9bGS) z5P4Mr{X@fGJLn_DYac4IS>RZ$L!CGXFIwx+(Oizkx@rvcw4%C7ih?i$6lH`Wnr#me z`vhp-O_ZiQ#LK=BbocZk>Ha!Y7e=D-Sv-bE$52(A3=!WMU2Qdx2t8nbQ5{i?Wf<;l z#`D^G)X}k|ts(ghBbG56gM$M|uv$QJEkh3b5X9jZQIP77#xfzECEZ15R}bo{i%}u+ zL04BZvV49dd$=FjDI7dYU|?u?2)zR@$v&<|h^HCCj3|tdGt>LB7abklsBLIPRY5pe zGZTC>W$-O#Vt8Z(T+3zXY%NDkO$}-#k>IlJAWrna*w`3E-a6>->nHcWKusmtgYYvb zO>@8)i90?%hGEhUkB(!A#2FnK!qCtVI!V6GWl1Cs6OtIyzntU$JO05AP%^M@G0!}i z=z;RKy?j#P!8Fh1JADEdQ=rcOq`m*ci{E^&ap$cgF2vrfx?tw)U*`Vsie-6HmP znm>PVRzBpO&95epmQpx8eb(+}d*8bzr{m~$dqxnBDXuoUxn<3{P><7}uJFAAGv$SI z-nsj>#kcQMl=((2d=<9j;XEhjt6zVi=1(z4Af5DPjjuzbkE3ad%%o_0VIP zEkp1pK6VqGzf?dAvSt7DB1d$h&MqP`Hk0dhowb-kjK6`b&L)xnP*7+%%=gKoQ5uIL z&aZH>HbnR(fO(13h`I(ylHHM+DMFmP9-^MyMVQT2#8}LM^C=2e#}+^sAA#=XLX?)| zqmR^(j7QtRGGBvYQ6$_fb|c*V65KD&Lv8yAa#?zi3K$6Rb%%}7cc{+sK}sYOX>23- zKhT5ALsQh&l%T6`6tT8n!1tmOlB2zmAP^wVc?X_~lTj?KM8GMaUJ{13_6`JHo(Z1y za#$Umj%ZUQBn6ryI?NAgUOywkT9ed`5G45;5FJT}-xX4qhI(OVFb6#^svyoU0G;6v ze@A0d`)?uLc_YFc4bTUn2DPQRlw)RqEu*$BuiC-|7;QzLS-(oh(E4R%JG;BK}R(Vm8QnxBQx z%hOOKDS?OaQe+c7EEh+hDE=;-FMkHF+q#Id-GRh=%Tbc)fk!q+ksNvlqQLXW3Nt|* z%Y@Y8VWJy5k;y&`@|e=tx|+DR-qu}31TB%iRONQ zhRPgtb+;qp`uiv;p>hBG8sy|;BZ+AD^8yxxX_-iH+=2vGU9jD*puV{UoU8KS+~15+ zNjloQM-gW^7hG>+m>rl7ze_WSmPJD<3Id-K1Q!EE)R(0r>CQ(;@;r!CH*KWFu~8{4 z0Q<&rjE)T=;@VtD)4kEx--o`g=XlXxJ5k@uE1#peJQ;2ejNx`i9|OIeU>uo)5Mz1N zmk|9-iy)eEfYfahIGJukRYM2bYqF3S`hdJ6aFF7l2|iOBS;9!7=Vvf5JV>;?8-9iq zcn&%c@}3~r&jFdywurJ+M`^wQzW4S_=wW9Q4c3);C@U{VX6$34rzgM%moB;{Z>XhIcczAjy>Kfb8($azu)7hZQN>M>) zBkImtq^11!DkpZv3p#RM?@?xj1)*)E!Zmjg* zyk4%_+Rx)}nwl=Zdw2eKg@G=ElObN;umAYa;u*j1-M;k5#*L*1`u+Fqs#cSYV37Gq zOPxq_F1EWgOM09?=&Potu~OLmXg`+_lRUj<@!KEmx)qx5-K5@pIQ7PfA>ReP)3UWl z945MLyi{gdIVv-XFVt@3Q>^9*@@< z%)a0e%I3SDqiMoZLo1$~{nG50lX)sC0tQX%(-cKJB=1@F%SbLI;Kfet-VJ^oJFWii&>qegwN4QSPyQ5o;^^Oq5v-I);um~6u-8Y;;j1O7s+L`dI#%5h^3WX=$Wbv0{UqtK9YL z_4QRuCbLbIMN|6aMJj~%d8^e%cY~&)qGtWp*(o~}a>`V?dsHkXdZLQd*5T`{RyX~n-o*L4* z|DmDbdV|@j3aJXJme)0{6bSY&0FW^bd&IwyC;tk>A^d!Ni&SYyBTsJvwGo?6zh)=f$KyKV)yI|2 zkw4HmzLT+3@Fy(`NH&`9Qd2WN)rG+LxPxrtW#2cTrzCZ9lJd*{ocRsRDwK$x2m}H_)zy^rK_IXdaISR^ANbB<>mmbw@NG0y zl|Xm@eLi%Sr2=;d5o)GBAP_O-e+L+plSd2OB=A+&QYKi%VWfOWDod943%K>r`GtwE zqNlsNy@xMw2?8m4+gtnE+c5_?`#LeJs%z=m3D^^WK+GU@rKc|f=MVCO0@)0w?&J-p z)H$=mVzM8n(p7x;<2O@r68lz!x$8q~ZS7h@uLv2Kya$iQ{28tnxW|iutqOeX_tfj@ zYc&PP_xYvB&uFnp**T8vs?;y3zB5NjDCiR{&L#Mcwv>9|_711$l3(Rvr{Cd4_>tsx z0Wmwby83hdlpyj!u_}J_An*RK2YUI3INIOAq2OrrL$q{4F*F}t8j6$O-DM3$2w@#CLc(4y3ME;Q z8;~Y;@H>d20(Q*aB{gc$(@*ReE;{dIwP}|+L`gvnx)%xT| zS;v4_Rlpc)GS^FCD6zG_jJQrqN1%W){b_y0U`7HcqmJWsl-^{WHr|j3|IC&_0l|IZ z7)Y624tMht3HCc9hhWJbU5re9@$C%6zS}I)0#ix+dA>4=8c@)%9`#a?InVRzi?fNo zKxKIev&}p6lmWAFzN6@UI8z>G5>M-1$Yn&`3u&BQ3Z_AE{G_6*w14>ZFe>EnS6zg--(>{TXF3_!HlvH zSlpaJMX-G=x~QbfJq9^rTs;cToESfILY(`wlq+25>M>DhWmR9aW7?ip?_X>v1j~#a zwc+yZDt7diAyj9wm-IKg3qLBw;1plF0Um&;of@AVUjp~pHu*oiq zkn)ZA;J*y1>j&OX!5)I(?F8GZrZTi0GL1?zW~QY#Qa+H zgAX8aWrJ1ke*txd*5NA1T4lRF!znbiBf98hvFfSR>_xehzfu&ULW@=TaG7sRN^q%* zdpDZV5JS-i3R*%`vl)be@Tv=Uv>MW?iTrW~5ES15D}|cHwxOjk*(^5Qg{H5EjP`0h zxp;hJHDmW?T6?1NU1L6>?TcxZ{t3rgCa&QCA;qO3YSe;7PGoSRJb&Iks&YUZ2wAl~c^#oPJr?rD)wL?3WeKia8^~ zWQT(4pf@74M0sh>K>_o!5$k_#lW?%^t{(H?(BS(PXhSqRfQ9AI$%Q1+h=#Vf+?DVf z-x)b35PF!|Z@&nh$)LZ;)18*vQ$xSG$aRr;b)W0@r6WQK2)6*}Tyo(E*yhenNZR9Lt z)DiKpj@5s$7ULHlL5GfE@XU*Y7ADvV5|8QKcEH~50wSqG9(o7~ez=h|GHxdcoF1MK zOWb*iPle7@W3vEZ__W9#*pLMdUg+A=PhVt0F5?qvYH^Y0x;G(>pd(KjJ&DWHuwE-J z1t7#9lHdst#z1%@R{~pqv}fb>Cg4~S#Xxc+r?UmBJlt@tZlMxYGB?vJ;+ee9MNgY> z#yE!;SQUE}U2D5nKOY)s2YvLIRPzMrmrj>AL-JL7!|hu2G6YmDsG2OZgfh`|l4wh_pp} z0m7+Sxs{G;L0zs*A%*yfgs)(;}yH5r}v zbKI|azqxV$9c$z`AYG%wF2Tpw#{ePnAz;X-@+&EouUxxY3@rIy~S>yc5|ukw}mf+ zn%&KYs1ap)|2U&6WkouBsTtJnotwo-$Pd3c{6}`%J}^x56JXa2lUYlFIhxx!5P|`r zCa&EK=)bXjuP0+H-%AZ*-!MYi8TLfWJ->JMj}E1GT4NgT(5xuVwe-LF`TAfHCQE+D zt|NTR74TH0NWJy(1!LaNs?fmTuxLUD-u48AahA5O6iKVcj*x3vs!q7uB;0NP;#6|? z0ZdOJsSN2eE@83uR?x;-eKc;Z42OZivE>_egKq;Na~tV^O5RyQCVQL`OZ}Ek$h?v4 zr2OnhwG_wL%y)f(GUHdVOChtJ5l#ked5v+`n#@K^v#n1gKaMa1B?P8B(jXgta$&9r zCfG6?24IN;^ZF$D<6L0LJAxtwOVG-RG3T@eQyd-t%rnl3IZIdm{;O-NL=zRKR)-0Z z1&ur{wGOi*1S8DkK$pTFfV6ufq~Y`G1u)0MtUg;%GxP;dJR=>`oUfy6h)tk(g;{cO z)l)5!soA3IVAPTGiW!_^IK3f2JU>s3i9?!mDX~Xa;bWb)R0|1BT!X!=-t&|V9X$AP z95G0n4ICgvHj4Wl!gfgDar`smC@aRW)5N6C*`$yyp!=Dt5LK%W>R90KHw}TflD=pk z4jU1{d69w0JD|phO|_;mj8Cmjl*!-T9KqMWx(#WUkoh&$2yg*wwpEjPMj2{gVBu(X z@^CLn%Z)4bbZa_<5}8^fK8dDbTDOgoSSwyi%ZO|UnseU9$FyE*4mL1mvc>r_??>Sk z?t3YpWGdUmx58HJ`*1Iay~lD-UQX8iTcH43&ACQd5^n4JWK_{)rn(z+nXRU>o$F}2 zb+}&?oOIf*yLbI5#bx;I>9WU2c(_-|ooZjAkRSZyCwyu4vwcqt4$HxoAlINTW)B}z z&IaO)lAxp<#idy5vdHL+0W>%LU3$-px*)^0zTS%Kz5CkMQOM_Mb`7Ngi4ZX6FMv!N zarB;dgVy_=!HlHwmmj(8d&0tUk39DF8{OMi@P5W^BsJIOJZCc+)bAnO4z>#L zvt1|F?B2?h&?4>wf+T^x<3|pj&R|1mB%zJ?s7cQ+k6yFS%Sk|m;1tzpCAcra8%cG$ zh8MZwOrOz=`)uM@9vDXXJ0oH;?y$V8ygr^L-_0jueTq{Y<(+Qkgu=CEosDAp^;N(KuBTEAm400g!uit@%q?c z1*D}|9}&+QZ{_=`3uM~b@6AiX311g?vc$UDn$GcYbe(bYbcg+LM&Fx|v6oCimwjjb z7;)ZzH#>pywqaW?;ySf;NVikZq1C#XiqPv_xm|HFQBikrjaO51W~^zn{tDqzL9o2= zPG<%53yL~FC}A2hrzF8^Ksu49=F((@H8`6XCIoJ;4uAi_xRCn*biKzA{ywXrb}z_3 zG_*s0SzyqII5dStcv^aD`gEjKki4ZbU8LNm)z!u4=yW~*oKY25je->?ghT40Mdt;J zmza1V*XquG6l`iaw>A(9_>2|%A@-AmfLNUn)RlEPg)(facjH_P`!?1w>_0zeA~#TG z*sCfKE%_1mb#eT7*I>>vHc*FU)as+PNeZ*D^Tov>{Ub((x1JfpY~9xq(og*?VMf9e z(o+J1Z)8`rQtEB5*WIrR60X)$<6LIgsCZX@??;)Wut^u9b46fs8}*mZ65_F6!y_J% z;04Q^S7wH?ZRf_Y^W#(JxxMtFko_9QX7-Fty=r%bvZzXb$K*>%XyU^bUPn01qtt6@&I=^zH&;7lp1EKeaWYE} zdL#b#u0%tYK+&}TfQ)Oc87O0oWvIf~Xo+N=3=hoU$p5GxQ3j;RBD?D?wKm0}{M{;$|UkLR58LYtcRjlYck* znw2*FGld_^vkYFUgskTVf31Hi?Q!7<(O1uSt1}lSJJx@m1nra9q{Olj?zeV!2{N9N zUTA(9ju*?08Wa_$J^CHwk=K_7XH`$L^MV||3Dj8rcWqVj>a;Nq&4cA1t}VbGkL2kCDPsF2P}tT?6b?Gka5Vk)k|tqZpKA* zB5${d4u?=?xu(DGPo7$~`Rej8G*gnC?=uym9a5{(-Ukq7u`Cng`ta?FLiYjyBJ5TE z7Oum5v0jCqn`;X%$VG5t&)Gl6L;>}*?lK*Ms6CxSmC_7VK=-JSzNOv5szpTe9S5qt zkfAV-UV~9z4Xb6n&5M8DHw|spYJQxc#4i$;d^p(LwN!794t_q{&ZbGewh>(z%=Pc_ zWF1nlfrEd8k$3=Dkp9+}lo(}SSacWoTw-8UZ2#&ZCBwBDCyH`b@wVOeI;NdN;(Nmj z$(ia5fY@@>+z#iSFeO3174C=0iPJHtyJc+L)Iy%?|53Q1>tOfn{$ip@4w#Fa^LqJN z28!L^=35D%o#ml8&GJ-nq?nT1+P}aOvC%Bqq)~n|>n0oBIahi6?ygU&Om+4u&k-A8 z+Gd#2x1@nwsIOvGx$(GS)QU0n20+owhcZZ-$%{H+h*>>X*J74B3D4;FvjcH<`wuuQO1C=Tv>N zu6dNxDJ#a0Yq@tfUaPAO*95x_;J$pvw^Znr8jGGdTY!-tS7kA-t9wtn8{G!1vQjE7 zy^FkUDuXLjL^LiuqGiH(ywdGismL4h%xi*TMVIGoz-I8eUAFo zYAVy7_zK4>50)_Y7`=*i# z1G)@~eO_GboCsx?UU_weqABZuWghOtFFfv^lXz`=_}qtIF1$YXsoM(f$*wHB0?h_j zNo-z=rih*!t709no?d5)uN8;x4V;R3RY9l?1YUFlDgC9=K^#UYkSh}Cb)6H#HA1|W z8Fib#>MAFRRJ_wm?M(?+-n6h+?uhSPcU>PYRvO(lDS0CC{zGL2+%%?dtEvYc)1Vim zadnT?mSHW7@X^%7A{#>iRiPW*CU3mL;2(&Nh!0_3gb;L30P|3i`W9eX2}~ZFOr~KM zf?T9u1EF2OO-0;U0;;?vw8GtfzX(T*!Uj<6-s7=zICZ!~t-rR8QYB_7c)h=r&5L|r zXY8ob%BGd(8h5!q;4gquQc(U2FEOUuv@$#2VryW}F!bjgUJDPl*;@p~ z3hj=UHBtanbD0lZdppO7?suFS`*PoI-kvy^eG1Lscy$tQ5v0*CSMq4vYS?_}Te^CA zV}n8RrdLI0bnOD)V;zL9VQj;*IQ8o0{TPKaU|0mXs1>mOJKp=a07~2OSIz zV{LQcfk{uD+-V4>i7N)JU+?V;=1G8dWx~JI68F_ zXcMI+`b9OXc_M689lMqpFFtDj{KvIsZ*a!qWP}AH2_CgZAbc4VXdZcF5>zX)!QgnB z*Z*Vwg`q!py1@hgnLbpXHw6psaA|vmMmbwgMq5P!KkJps#*Z#N4x2s7YYMp#S@Dn) z-|OqBQ*XW^kj}m9<7yxxEHR9fqB~xMmo~N12Gt}lz^b6Kt33v7kWp~QwkWZ+5YT2} znyeee@!v4EpFkh;S&m+1Cem~Rbpy`nulyC5UD| z5rS5e?7pgfT`K!%s86SJPsaPStfu;gr54SCv?BXn`)hz680t)gx2GR&2W|cnkfd0k z5KNew`X{U75E<*J=l=w$)l9ejuH)D=+-B{F_9wyO<&G0y`875%CWN1zCvO%%RCIVQUX)1Ph;^kGruO87~kuZF%LqKgABt z{5i)yqa&$_x;r#|$5{^YJMmsN69UQ-$uam}98!C2325azc9w?WZ(^c9q^_m#{XOJq zwtsJS`t-usivvSH@caq13{uT?$-KH@t~NV=;gl^;aj2lTHBsaD13h|h0vt&sH@@w+ zBd3KU7q<~jYJU4UZ;V#0xXAFk3`pKBid7kdJ&$#7_D0`tpa|BwO1ftVB=5n(@^k zrWK!OJ6#p0x(jxj?CsNT%4p<>XJK_dA(bH%IZu(oP}g|Iq-Qjx1$vl)1kG-LzP{(} zn&gl29M9W{JUO+^&G{(lmiK=?So>U3VjWF(;xk$IN#R?*tN`cc+r8x?!|8XVpI%3I z+UO5S5wv_V6ssPKq229bWzFTO~K~Imvb!hr#{=pMN z9o*oO%U>A2JYQAP{l)N0z-6qW^%lk}d9jVxjz;uH-dmm4$-k$Cxes0ULPdUA zPLFrdDQ9o`JJ1a_&lvvOE36zUYF}_y9%LsRIg1nl#MR(1t9_qXYJGqguEr$0QjeOK zMO*7)560f4-65x@Z6Q+H9zHVtgi2PZ1E2zO5R8UfSeTg z>KjEgNcI<(!EU(PxlG*d6q}or|9+oV8{UO_x7l${GjEPZ@~U6r6S!m$FwteIs>~lW z&=tKr2MaRHwuQ9|mD|~MmRc{pZKQO!eQfc(s>WYJ7YR!Y0ISpJ0-Htd7Mibs(ti

    We6BCTF}h;}Jf zU5)}U2PtvmPpEQ@st!07X9~DR_KT~Tn?>3B{OL%I+_a#z6^>39+Pq=(4F7b*=RnQ3 zjabsr>UH@MbJjMC{Ry~M6|5R1_J&R8h1_XvXZq^4IPV74e*@kJJKgbeyX@j-6a^;sdvac)A!?rrL3!^!z{;)K$E z>!Ez;>EW+In;cVyWCje;)*VTcx^>Rw$4d;bi_xpTQLuPx^cMLA4?7RRasu+6Yo^8! zTtN{b8GgxD%l8dBA8fy+lO_$zKW8enR!3LL$gmoXD6nQ-;lZq(+q8cbao>$?KGdZ4 z=~gSXhQF2&+`RYSrVmy@oMxtDlX3ph4R>yHLD_2Ged94Nvs(Po9j7_r^pdY`-_%pq z?a%+?qg<~4Z)M74F;5JNU;s@I$F|na3Gxv`$c%^Nc?Tn9V|olBQN2ZgNrHdm=dc3%HL7{S0)_5_+AgSPqwa!XS>Eg48TMC)MI(%fnNR% zi8y6xFN)ZJUC?JBD}>viJg`y;YJe?_;Jsdd$S>UtQB7S*^?3x&@N3$?(aq_$C zOY!~xHfX6uK(E%btAH*ps6JIdqp|OW>M-&Y@vOR|FGU>m0GRXN@_2*oON`&(W0s5l z&5bL*wv@DDHuh{mkoFKyUcT=Irnqw?1A2tt{Jt}_=Fv~-m;RwVsdT-YcCNVo>u%m$ zMB|41Wk;u8N1<@b@BXN6LA%baM#~ewm0#CX`T^8??O6wn-qkbaLftK^j9xx+$b49? z(&IS5vNP`U!OOK?$UaGzoV`(S&92j2a@OD?CZ#1e=8QA1aWq~FIb(PbYL&m&E|<5# z6R=m&{J@c*VE?6aU!+;@`1ciGLup8|zL;_WzW;88KR>n%A$BrM^(KhDj-4^Fm2^Qy z)A)<$x*eol9=NQHh&B1x!5BzN@XcljR^Pzjr70z@t)0M~SA8IkZK`o`1%{k4NISQJ zPiYgWvdXJn{X0NaB*qpc1KYrR73UU#tGX{3wl6;jz9~u;fKQF$T4XlR=Yl*4RaujO z`Kic=fs@idJ-LzYt4bokR>(Cny+1MTzJ8kaIi1n_@L&NUJ2AJ(&aU6kP8`m+rB z?jGG!Wu1W({xUr9Wi0d6pN~WVN;CzIE_@yTUOq_@_+b0jyWyx0d)w>2h9L$p`nF$w zx5wza6C1aSR$5YVp$AAV#)LB9g@Wq;-UUz@1qOO%oNeo8*d9qkikptR(*|kPF#cle zmA6!gb6)&=$R9(x>Qp>)w#13JAK=$r^ca%^%$WAG)(J*G=!?X(1M|28^Njc%U4S0t zm%7`+a$^N3f_IV1%M3`BuF}dJhZ=(V)x~Zgs7R>oOhY|i0`AO@DgJ6bQx|4Cb2 zFR~7lvfX#u0;xsE^=2qtcU4r*C!^)Rj^A5#!UZ%U3Vm+;T3QhzRYYd;VfV$y$Od3|pF(xvS zH44sSBhdNiTz$}`lvPWOOEvU2%>?h@}V!NPnuFUqV$(y_H(pb9lHW#~B~8j6W-YUBWY` zL8@3tEKTT{U*sdiyz6RQNE5o=wf^-$apmGN1Ax~Z+I_qcu8OMYB)wFE(W|qw>%pgL zXkO#x73CL98y=XgIokB;#d#VFE}4g&MY zKLVIjfFBB-eRub4{G{1AkfgsWrYVpr&81|Kzu=xJS%DYDi$}wdy4dezZN-)I&NdWR zqS#jeO2Nn4mM}BDrUSUmW*T1r1e<3@1MgN>Fon@yDd(sjP8;%P7Y4F1Cd#Cg-fZ^` zv2bwAUA&drr?8x0;kL2ukAQE?%6=d+~bpY~SZ`=r% zzvR8&*;_4o!gYW9Qg{q`@FF=PpF~5;G6tTIA;}a9oKxedkSbCD;sMU=CRJrEFAJST zgtF1CT+8{7Kz`Z*ar9k9APAq4Ghb=bf|6cM9-k}Np&uQI&=RM$4asY3I zr+p-inF#Gx=@@Xk(O)5Od99B5f~u&#ugZ#J+Vlh82w-po5svoTt^)4F!_Ntk#i=d# zFiR}UJL>2ofQyrB0{qfVN(@I!pn+1R;HG<=OVW|$ZnFsSD&yjWMSL|rl0gU0Pz z0UHhA1Q5QLMSI*|q(iEtpibDWSp{Y#k)I;uiYn(tQ5CncKnw~0D8WIWqAIjXnkK33 zc24PllmH1&6*B-^lD`wl-8fr^wdIp)2)E(BUUp#J^EKSl43d!R@f9R16$9i3NbVu3 zf=)p#OR1v&G9*kGgwRJmXdK%fTvnIJZ(D^;)`jC#IUK8r?0o03PUzs>Y)M9lQOp>+ zLlHqh0`jA$e9d4|^V9I)>1xwkN8vi{aYOf{8kdXKa2^7=he(xzQ>TkA^V#E^NLB#; zlWW_B5Kh3VEp24{g^!&{l{=*LiJkxcuM&s@Y{iOZ^P9L7|H-?bsGj2R^E^RZKtp)=R^Rwbufg)vjzWTv*AhuyhRZHb#-*`5GWF2s>)ZUj`U^P#k^XbT z)HyPok?Zo#;R|n5f1BfT0KsU5-<-y87L-uqBK!4_$6hxWfqWj1Ve?3Fr2imVKeQqH z=HR>=$m9Il8%p~0UMWx9shINIW62e2&jGw?~89mkKU%?N; z(w!zVVLy-RH7<#|QeIj3U_5jj6(9I$U&cS9z(KP`Yaa6_Flz{zQQvsW^R`2Vgw`s6L<2I9($o5A`|1UU#+u z1s&&W3y$6vBck@(r#AbB#ec4DQ58#%jfl$K8fAJ-_zA*4RlYPE3Rs~!yMk%=DZ4DV zt$whJX*SfHTrOVZ@;wrs;TgiW5d0%2Iaiiy|7<2Rp?=k&hZ6QLWuyIs^9;>tF`KW9 z-v?};)N@R4_(C=B5@;wS2*4kdq@+|0w%e}#| zwE?KC8-Tt~4p?Z_CdZStli=2?eu!2_R1z6)e`AfRPzN$U^@pW5l&|uTKP;mtrI&a$ z<#P?bj}!-bmJiob-E)?WcAor=%ox#@Ise8gQ6=+X}U51_P|w8195rrTN|Jza=N zrTnTb4woy`7VM+QMTj+68h@FBF=XhUH2|zf0@ynJ#VvW5e;knBzRqDcG7PepSM&1H zJf9aCyQA+$em4Jr%yPorrA0S$r2Ac*P=*UM$|h^i_18j`U*o|(I_+%4uH|2)_>mns u02ogMP000yS1^@s6cz2e)00001b5ch_0Itp) z=>Px#1ZP1_K>z@;j|==^1poj532;bRa{vGmbN~PnbOGLGA9w%&0@g`HK~zXfy;SW> zQ(+YU-Mj62o6hAd6-mR2G6KuYRu~0=R6>N%8$vHwU+POy{Re%k4}ItbN<>h^3WFd9 zSy9L=Vx`k;6H&4kU-B(-W3t^{?>f(&_pag88QA%B@AI5p3`06Z;(}T;896k%yQr;(lcjPM72*4K^7F zp|YVJ&QC*tfk$qR1Z0S1mk6p6@CCA`gy>L*?Bj`|h_I`zm67qwb23#zZID6p+g zL+P58F%Z#c!2S)H>VY=V3{;Y5aQT@R0cn1Xt~fksBn?cn04#?hN04t_5f8#Hu9p`g z+bSZgMCot@Vj@N_yN7YUxho-?7HUsJ`wwu`3FfZ?uy_*TM#X08zA?sxeepbpx}#eG zUroBrbl=GS(k2#vZCf3ed#OzBoo= z>7)OurVcf@XVi~3-Z2=(C;;=5NViNX=GNgYu!yGkBIkR%4%EKK3(p8l6u{cX5{0M3 zIBCy^duR&1;{gb?Q|ftGLBXn2Vz3=M@-pV=r!Qk7WlL{6@$t)qKALJvq#0T^(rQ)* z#=u6pInM6HuC=yAX%>FFTF%+Am$inkok{R}xMgHJJ_C?_56OZyf~ zu3s|YleJfUW0A6ZZIPR;eaVKXen~UYcYz*HHdRZpC4(#_x#s%^)39)n%^;gG00000 LNkvXXu0mjfMrm;Y literal 0 HcmV?d00001 diff --git a/auth/auth-gui/theme/onap/options_up.png b/auth/auth-gui/theme/onap/options_up.png new file mode 100644 index 0000000000000000000000000000000000000000..7414dab5d20a7451b47cd840a7a6fcbe06f4a99d GIT binary patch literal 826 zcmV-A1I7G_P)P000yS1^@s6cz2e)00001b5ch_0Itp) z=>Px#1ZP1_K>z@;j|==^1poj532;bRa{vGmbN~PnbOGLGA9w%&0?$cAK~zXfy_N4v zQ&AYlzq{Rgw;B$r*-*1G1aT&&=3bN%2w^aSAS+E23hYhvqBp(kKd`7b^&*p^up*%# zT9Fj=Q%glN3Jbx0kZCu>BeVa zHQg;p3)1p*7}XcM@Mw5EEs$ZU?J7O@1cPJKP=g9YlZf+sx1iavX-Tk@kb&=B>~4Dn z_oN@9QG{SHAgo59`hwV+Z$;O!N|?kINnuIbGLWm(jMFoh0XiO_g1b4Gw|o2}?MUbQGFVI{p^CvoUT zKLHpdDH@Q46%<&_s4L3>`xQjo`O-=Wy(1H-xzxRM$TQl&&tT-Ij{pJ;)FPE%C8pwb zV+F3)m%~|-gAh|R5MP(b2oK+mqVmFX1VYMRumzRO1VT7*_Z=o?qAlV9xWcm`RNL2~ z(3YW%+w03s<19)D;FD%a#MwP|$aEQ%*gG3P$H&7H zx(RfM=ZB9jS+slH`;PofTs>I2C?LLIw^`7(uLP>cuT`Xpa^+Be%xPNG+Ttu^XIa3e z17P%gR8f0eM;yAlQjr?U*5k_2?J$Z0*i3-;pL4Kgl^kWpA4o6Rw_|V=`I%6xI@^2i$6zC~R8uG7O8G!8i}uH+wEic{1^ySvZ + + + 4.0.0 + + org.onap.aaf.auth + parent + 2.1.0-SNAPSHOT + ../pom.xml + + + aaf-auth-hello + AAF Auth Hello Service + Hello Service Component for testing AAF Auth Access + + + + + + + org.onap.aaf.auth + aaf-auth-core + + + + org.onap.aaf.cadi + aaf-cadi-aaf + + + + + + + + org.apache.maven.plugins + maven-jar-plugin + + + **/*.class + + + 2.3.1 + + + + + org.apache.maven.plugins + maven-deploy-plugin + + true + + + + org.codehaus.mojo + appassembler-maven-plugin + + + + org.onap.aaf.auth.hello.AAF_Hello + hello + + cadi_prop_files=${project.conf_dir}/org.osaaf.hello.props + + + + + + + + + + + nexus + attarch-releases + http://mavencentral.it.att.com:8084/nexus/content/repositories/attarch-releases + + + nexus + attarch-snapshots + http://mavencentral.it.att.com:8084/nexus/content/repositories/attarch-snapshots + + + diff --git a/auth/auth-hello/src/main/config/.gitignore b/auth/auth-hello/src/main/config/.gitignore new file mode 100644 index 00000000..b8a5bee8 --- /dev/null +++ b/auth/auth-hello/src/main/config/.gitignore @@ -0,0 +1,2 @@ +/log4j.properties +/logging.properties diff --git a/auth/auth-hello/src/main/config/hello.props b/auth/auth-hello/src/main/config/hello.props new file mode 100644 index 00000000..055b15fb --- /dev/null +++ b/auth/auth-hello/src/main/config/hello.props @@ -0,0 +1,29 @@ +## +## AUTHZ GUI (authz-gui) Properties +## + +hostname=_HOSTNAME_ + +## DISCOVERY (DME2) Parameters on the Command Line +AFT_LATITUDE=_AFT_LATITUDE_ +AFT_LONGITUDE=_AFT_LONGITUDE_ +AFT_ENVIRONMENT=_AFT_ENVIRONMENT_ +DEPLOYED_VERSION=_ARTIFACT_VERSION_ + +## Pull in common/security properties + +cadi_prop_files=_COMMON_DIR_/com.att.aaf.common.props:_COMMON_DIR_/com.att.aaf.props + +##DME2 related parameters +DMEServiceName=service=com.att.authz.authz-gui/version=_MAJOR_VER_._MINOR_VER_._PATCH_VER_/envContext=_ENV_CONTEXT_/routeOffer=_ROUTE_OFFER_ +AFT_DME2_PORT_RANGE=_AUTHZ_HELLO_PORT_RANGE_ + +# Turn on both AAF TAF & LUR 2.0 +aaf_url=https://DME2RESOLVE/service=com.att.authz.AuthorizationService/version=_MAJOR_VER_._MINOR_VER_/envContext=_ENV_CONTEXT_/routeOffer=_ROUTE_OFFER_ +# 1 min cache changes (when left alone) +aaf_user_expires=60000 + +# CSP +csp_domain=PROD + + diff --git a/auth/auth-hello/src/main/java/org/onap/aaf/auth/hello/AAF_Hello.java b/auth/auth-hello/src/main/java/org/onap/aaf/auth/hello/AAF_Hello.java new file mode 100644 index 00000000..97448bdd --- /dev/null +++ b/auth/auth-hello/src/main/java/org/onap/aaf/auth/hello/AAF_Hello.java @@ -0,0 +1,129 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + + +package org.onap.aaf.auth.hello; + +import java.util.Map; + +import javax.servlet.Filter; + +import org.onap.aaf.auth.cache.Cache.Dated; +import org.onap.aaf.auth.env.AuthzEnv; +import org.onap.aaf.auth.env.AuthzTrans; +import org.onap.aaf.auth.env.AuthzTransFilter; +import org.onap.aaf.auth.rserv.HttpCode; +import org.onap.aaf.auth.rserv.HttpMethods; +import org.onap.aaf.auth.server.AbsService; +import org.onap.aaf.auth.server.JettyServiceStarter; +import org.onap.aaf.cadi.CadiException; +import org.onap.aaf.cadi.LocatorException; +import org.onap.aaf.cadi.PropAccess; +import org.onap.aaf.cadi.aaf.v2_0.AAFAuthn; +import org.onap.aaf.cadi.aaf.v2_0.AAFLurPerm; +import org.onap.aaf.cadi.aaf.v2_0.AAFTrustChecker; +import org.onap.aaf.cadi.config.Config; +import org.onap.aaf.cadi.register.Registrant; +import org.onap.aaf.cadi.register.RemoteRegistrant; +import org.onap.aaf.misc.env.APIException; +import org.onap.aaf.misc.env.Env; + +public class AAF_Hello extends AbsService { + public enum API{TOKEN_REQ, TOKEN,INTROSPECT, ERROR,VOID}; + public Map cacheUser; + public AAFAuthn aafAuthn; + public AAFLurPerm aafLurPerm; + + /** + * Construct AuthzAPI with all the Context Supporting Routes that Authz needs + * + * @param env + * @param si + * @param dm + * @param decryptor + * @throws APIException + */ + public AAF_Hello(final AuthzEnv env) throws Exception { + super(env.access(), env); + + aafLurPerm = aafCon().newLur(); + // Note: If you need both Authn and Authz construct the following: + aafAuthn = aafCon().newAuthn(aafLurPerm); + + String aaf_env = env.getProperty(Config.AAF_ENV); + if(aaf_env==null) { + throw new APIException("aaf_env needs to be set"); + } + + // Initialize Facade for all uses + AuthzTrans trans = env.newTrans(); + StringBuilder sb = new StringBuilder(); + trans.auditTrail(2, sb); + trans.init().log(sb); + + API_Hello.init(this); +} + + /** + * Setup XML and JSON implementations for each supported Version type + * + * We do this by taking the Code passed in and creating clones of these with the appropriate Facades and properties + * to do Versions and Content switches + * + */ + public void route(HttpMethods meth, String path, API api, HttpCode code) throws Exception { + String version = "1.0"; + // Get Correct API Class from Mapper + route(env,meth,path,code,"text/plain;version="+version,"*/*"); + } + + @Override + public Filter[] filters() throws CadiException, LocatorException { + try { + return new Filter[] { + new AuthzTransFilter(env,aafCon(), + new AAFTrustChecker((Env)env)) + }; + } catch (NumberFormatException e) { + throw new CadiException("Invalid Property information", e); + } + } + + @SuppressWarnings("unchecked") + @Override + public Registrant[] registrants(final int port) throws CadiException, LocatorException { + return new Registrant[] { + new RemoteRegistrant(aafCon(),app_name,app_version,port) + }; + } + + public static void main(final String[] args) { + PropAccess propAccess = new PropAccess(args); + try { + AAF_Hello service = new AAF_Hello(new AuthzEnv(propAccess)); +// env.setLog4JNames("log4j.properties","authz","hello","audit","init","trace"); + JettyServiceStarter jss = new JettyServiceStarter(service); + jss.start(); + } catch (Exception e) { + e.printStackTrace(); + } + } +} diff --git a/auth/auth-hello/src/main/java/org/onap/aaf/auth/hello/API_Hello.java b/auth/auth-hello/src/main/java/org/onap/aaf/auth/hello/API_Hello.java new file mode 100644 index 00000000..e2252236 --- /dev/null +++ b/auth/auth-hello/src/main/java/org/onap/aaf/auth/hello/API_Hello.java @@ -0,0 +1,88 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.hello; + +import javax.servlet.ServletOutputStream; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.onap.aaf.auth.env.AuthzTrans; +import org.onap.aaf.auth.hello.AAF_Hello.API; +import org.onap.aaf.auth.rserv.HttpCode; +import org.onap.aaf.auth.rserv.HttpMethods; +import org.onap.aaf.misc.env.Env; +import org.onap.aaf.misc.env.TimeTaken; + +/** + * API Apis + * @author Jonathan + * + */ +public class API_Hello { + + + // Hide Public Constructor + private API_Hello() {} + + /** + * Normal Init level APIs + * + * @param oauthHello + * @param facade + * @throws Exception + */ + public static void init(final AAF_Hello oauthHello) throws Exception { + //////// + // Overall APIs + /////// + oauthHello.route(HttpMethods.GET,"/hello/:perm*",API.TOKEN,new HttpCode(oauthHello,"Hello OAuth"){ + @Override + public void handle(AuthzTrans trans, HttpServletRequest req, HttpServletResponse resp) throws Exception { + resp.setStatus(200 /* OK */); + ServletOutputStream os = resp.getOutputStream(); + os.print("Hello AAF "); + String perm = pathParam(req, "perm"); + if(perm!=null && perm.length()>0) { + os.print('('); + os.print(req.getUserPrincipal().getName()); + TimeTaken tt = trans.start("Authorize perm", Env.REMOTE); + try { + if(req.isUserInRole(perm)) { + os.print(" has "); + } else { + os.print(" does not have "); + } + } finally { + tt.done(); + } + os.print("Permission: "); + os.print(perm); + os.print(')'); + } + os.println(); + + trans.info().printf("Said 'Hello' to %s, Authentication type: %s",trans.getUserPrincipal().getName(),trans.getUserPrincipal().getClass().getSimpleName()); + } + }); + + } +} diff --git a/auth/auth-hello/src/test/java/org/onap/aaf/auth/hello/test/HelloTester.java b/auth/auth-hello/src/test/java/org/onap/aaf/auth/hello/test/HelloTester.java new file mode 100644 index 00000000..84625281 --- /dev/null +++ b/auth/auth-hello/src/test/java/org/onap/aaf/auth/hello/test/HelloTester.java @@ -0,0 +1,81 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.hello.test; + +import java.net.ConnectException; +import java.net.HttpURLConnection; +import java.net.URI; +import java.net.URISyntaxException; + +import org.onap.aaf.auth.common.Define; +import org.onap.aaf.cadi.CadiException; +import org.onap.aaf.cadi.LocatorException; +import org.onap.aaf.cadi.PropAccess; +import org.onap.aaf.cadi.aaf.v2_0.AAFConHttp; +import org.onap.aaf.cadi.aaf.v2_0.AAFLocator; +import org.onap.aaf.cadi.client.Future; +import org.onap.aaf.cadi.client.Rcli; +import org.onap.aaf.cadi.client.Retryable; +import org.onap.aaf.cadi.config.SecurityInfoC; +import org.onap.aaf.misc.env.APIException; + +public class HelloTester { + + public static void main(String[] args) { + // Do Once and ONLY once + PropAccess access = new PropAccess(args); + try { + Define.set(access); + String uriPrefix = access.getProperty("locatorURI","https://aaftest.test.att.com"); + + SecurityInfoC si = SecurityInfoC.instance(access, HttpURLConnection.class); + AAFLocator loc = new AAFLocator(si,new URI(uriPrefix+"/locate/"+Define.ROOT_NS()+".hello:1.0")); + AAFConHttp aafcon = new AAFConHttp(access,loc,si); + + // + String pathinfo = "/hello"; + final int iterations = Integer.parseInt(access.getProperty("iterations","5")); + System.out.println("Calling " + loc + " with Path " + pathinfo + ' ' + iterations + " time" + (iterations==1?"":"s")); + for(int i=0;i () { + @Override + public Void code(Rcli client) throws CadiException, ConnectException, APIException { + Future fs = client.read("/hello","text/plain"); + if(fs.get(5000)) { + System.out.print(fs.body()); + } else { + System.err.println("Ooops, missed one: " + fs.code() + ": " + fs.body()); + } + return null; + + } + }); + Thread.sleep(500L); + } + } catch (CadiException | LocatorException | URISyntaxException | APIException | InterruptedException e) { + e.printStackTrace(); + } + + + } + +} diff --git a/auth/auth-locate/.gitignore b/auth/auth-locate/.gitignore new file mode 100644 index 00000000..3fea7c64 --- /dev/null +++ b/auth/auth-locate/.gitignore @@ -0,0 +1,6 @@ +/target/ +/.classpath +/logs/ +/.settings/ +/tokens/ +/.project diff --git a/auth/auth-locate/pom.xml b/auth/auth-locate/pom.xml new file mode 100644 index 00000000..4fb54db3 --- /dev/null +++ b/auth/auth-locate/pom.xml @@ -0,0 +1,113 @@ + + + + 4.0.0 + + org.onap.aaf.auth + parent + 2.1.0-SNAPSHOT + ../pom.xml + + + aaf-auth-locate + AAF Auth Locate + Location Service for AAF Auth Components + + + true + + + + + org.onap.aaf.auth + aaf-auth-core + + + + org.onap.aaf.auth + aaf-auth-cass + + + + org.onap.aaf.cadi + aaf-cadi-aaf + + + + + + + org.jvnet.jaxb2.maven2 + maven-jaxb2-plugin + 0.8.2 + + + + generate + + + + + src/main/xsd + + + + + + org.apache.maven.plugins + maven-deploy-plugin + + true + + + + org.codehaus.mojo + appassembler-maven-plugin + + + + org.onap.aaf.auth.locate.AAF_Locate + locate + + cadi_prop_files=${project.conf_dir}/org.osaaf.locate.props + + + + + + + + + + + nexus + attarch-releases + http://mavencentral.it.att.com:8084/nexus/content/repositories/attarch-releases + + + nexus + attarch-snapshots + http://mavencentral.it.att.com:8084/nexus/content/repositories/attarch-snapshots + + + diff --git a/auth/auth-locate/src/main/.gitignore b/auth/auth-locate/src/main/.gitignore new file mode 100644 index 00000000..e69de29b diff --git a/auth/auth-locate/src/main/config/.gitignore b/auth/auth-locate/src/main/config/.gitignore new file mode 100644 index 00000000..429128d5 --- /dev/null +++ b/auth/auth-locate/src/main/config/.gitignore @@ -0,0 +1,2 @@ +/authGW.props +/log4j.properties diff --git a/auth/auth-locate/src/main/java/org/onap/aaf/auth/locate/AAF_Locate.java b/auth/auth-locate/src/main/java/org/onap/aaf/auth/locate/AAF_Locate.java new file mode 100644 index 00000000..92fc88c7 --- /dev/null +++ b/auth/auth-locate/src/main/java/org/onap/aaf/auth/locate/AAF_Locate.java @@ -0,0 +1,243 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + + +package org.onap.aaf.auth.locate; + +import java.net.URI; +import java.util.Map; + +import javax.servlet.Filter; + +import org.onap.aaf.auth.cache.Cache; +import org.onap.aaf.auth.cache.Cache.Dated; +import org.onap.aaf.auth.dao.CassAccess; +import org.onap.aaf.auth.dao.cass.LocateDAO; +import org.onap.aaf.auth.direct.DirectLocatorCreator; +import org.onap.aaf.auth.direct.DirectRegistrar; +import org.onap.aaf.auth.env.AuthzEnv; +import org.onap.aaf.auth.env.AuthzTrans; +import org.onap.aaf.auth.env.AuthzTransFilter; +import org.onap.aaf.auth.locate.api.API_AAFAccess; +import org.onap.aaf.auth.locate.api.API_Api; +import org.onap.aaf.auth.locate.api.API_Find; +import org.onap.aaf.auth.locate.api.API_Proxy; +import org.onap.aaf.auth.locate.facade.LocateFacadeFactory; +import org.onap.aaf.auth.locate.facade.LocateFacade_1_0; +import org.onap.aaf.auth.locate.mapper.Mapper.API; +import org.onap.aaf.auth.rserv.HttpMethods; +import org.onap.aaf.auth.server.AbsService; +import org.onap.aaf.auth.server.JettyServiceStarter; +import org.onap.aaf.cadi.CadiException; +import org.onap.aaf.cadi.Locator; +import org.onap.aaf.cadi.LocatorException; +import org.onap.aaf.cadi.PropAccess; +import org.onap.aaf.cadi.aaf.v2_0.AAFAuthn; +import org.onap.aaf.cadi.aaf.v2_0.AAFConHttp; +import org.onap.aaf.cadi.aaf.v2_0.AAFLurPerm; +import org.onap.aaf.cadi.aaf.v2_0.AAFTrustChecker; +import org.onap.aaf.cadi.aaf.v2_0.AbsAAFLocator; +import org.onap.aaf.cadi.config.Config; +import org.onap.aaf.cadi.register.Registrant; +import org.onap.aaf.misc.env.APIException; +import org.onap.aaf.misc.env.Data; +import org.onap.aaf.misc.env.Env; + +import com.datastax.driver.core.Cluster; + +public class AAF_Locate extends AbsService { + private static final String DOT_LOCATOR = ".locator"; + + private static final String USER_PERMS = "userPerms"; + private LocateFacade_1_0 facade; // this is the default Facade + private LocateFacade_1_0 facade_1_0_XML; + public Map cacheUser; + public final AAFAuthn aafAuthn; + public final AAFLurPerm aafLurPerm; + private Locator gui_locator; + public final long expireIn; + private final Cluster cluster; + public final LocateDAO locateDAO; + private Locator dal; + private final String aaf_service_name; + private final String aaf_gui_name; + + + /** + * Construct AuthzAPI with all the Context Supporting Routes that Authz needs + * + * @param env + * @param si + * @param dm + * @param decryptor + * @throws APIException + */ + public AAF_Locate(final AuthzEnv env) throws Exception { + super(env.access(), env); + aaf_service_name = app_name.replace(DOT_LOCATOR, ".service"); + aaf_gui_name = app_name.replace(DOT_LOCATOR, ".gui"); + + expireIn = Long.parseLong(env.getProperty(Config.AAF_USER_EXPIRES, Config.AAF_USER_EXPIRES_DEF)); + + // Initialize Facade for all uses + AuthzTrans trans = env.newTransNoAvg(); + + cluster = org.onap.aaf.auth.dao.CassAccess.cluster(env,null); + locateDAO = new LocateDAO(trans,cluster,CassAccess.KEYSPACE); + + // Have AAFLocator object Create DirectLocators for Location needs + AbsAAFLocator.setCreator(new DirectLocatorCreator(env, locateDAO)); + + aafLurPerm = aafCon().newLur(); + // Note: If you need both Authn and Authz construct the following: + aafAuthn = aafCon().newAuthn(aafLurPerm); + + + facade = LocateFacadeFactory.v1_0(env,locateDAO,trans,Data.TYPE.JSON); // Default Facade + facade_1_0_XML = LocateFacadeFactory.v1_0(env,locateDAO,trans,Data.TYPE.XML); + + synchronized(env) { + if(cacheUser == null) { + cacheUser = Cache.obtain(USER_PERMS); + Cache.startCleansing(env, USER_PERMS); + } + } + + + //////////////////////////////////////////////////////////////////////////// + // Time Critical + // These will always be evaluated first + //////////////////////////////////////////////////////////////////////// + API_AAFAccess.init(this,facade); + API_Find.init(this, facade); + API_Proxy.init(this, facade); + + //////////////////////////////////////////////////////////////////////// + // Management APIs + //////////////////////////////////////////////////////////////////////// + // There are several APIs around each concept, and it gets a bit too + // long in this class to create. The initialization of these Management + // APIs have therefore been pushed to StandAlone Classes with static + // init functions + API_Api.init(this, facade); + + //////////////////////////////////////////////////////////////////////// + // Default Function + //////////////////////////////////////////////////////////////////////// + API_AAFAccess.initDefault(this,facade); + + } + + + /** + * Setup XML and JSON implementations for each supported Version type + * + * We do this by taking the Code passed in and creating clones of these with the appropriate Facades and properties + * to do Versions and Content switches + * + */ + public void route(HttpMethods meth, String path, API api, LocateCode code) throws Exception { + String version = "1.0"; + // Get Correct API Class from Mapper + Class respCls = facade.mapper().getClass(api); + if(respCls==null) throw new Exception("Unknown class associated with " + api.getClass().getName() + ' ' + api.name()); + // setup Application API HTML ContentTypes for JSON and Route + String application = applicationJSON(respCls, version); + route(env,meth,path,code,application,"application/json;version="+version,"*/*","*"); + + // setup Application API HTML ContentTypes for XML and Route + application = applicationXML(respCls, version); + route(env,meth,path,code.clone(facade_1_0_XML,false),application,"text/xml;version="+version); + + // Add other Supported APIs here as created + } + + public void routeAll(HttpMethods meth, String path, API api, LocateCode code) throws Exception { + route(env,meth,path,code,""); // this will always match + } + + + /* (non-Javadoc) + * @see org.onap.aaf.auth.server.AbsServer#_newAAFConHttp() + */ + @Override + protected AAFConHttp _newAAFConHttp() throws CadiException { + try { + if(dal==null) { + dal = AbsAAFLocator.create(aaf_service_name,Config.AAF_DEFAULT_VERSION); + } + // utilize pre-constructed DirectAAFLocator + return new AAFConHttp(env.access(),dal); + } catch (APIException | LocatorException e) { + throw new CadiException(e); + } + + } + + public Locator getGUILocator() throws LocatorException { + if(gui_locator==null) { + gui_locator = AbsAAFLocator.create(aaf_gui_name,Config.AAF_DEFAULT_VERSION); + } + return gui_locator; + } + + + @Override + public Filter[] filters() throws CadiException, LocatorException { + try { + return new Filter[] { + new AuthzTransFilter(env, aafCon(), + new AAFTrustChecker((Env)env) + )}; + } catch (NumberFormatException e) { + throw new CadiException("Invalid Property information", e); + } + } + + @SuppressWarnings("unchecked") + @Override + public Registrant[] registrants(final int port) throws CadiException { + return new Registrant[] { + new DirectRegistrar(access,locateDAO,app_name,app_version,port) + }; + } + + @Override + public void destroy() { + Cache.stopTimer(); + if(cluster!=null) { + cluster.close(); + } + super.destroy(); + } + + public static void main(final String[] args) { + PropAccess propAccess = new PropAccess(args); + try { + AAF_Locate service = new AAF_Locate(new AuthzEnv(propAccess)); +// service.env().setLog4JNames("log4j.properties","authz","gw","audit","init","trace"); + JettyServiceStarter jss = new JettyServiceStarter(service); + jss.start(); + } catch (Exception e) { + e.printStackTrace(); + } + } +} diff --git a/auth/auth-locate/src/main/java/org/onap/aaf/auth/locate/BasicAuthCode.java b/auth/auth-locate/src/main/java/org/onap/aaf/auth/locate/BasicAuthCode.java new file mode 100644 index 00000000..ac348f3f --- /dev/null +++ b/auth/auth-locate/src/main/java/org/onap/aaf/auth/locate/BasicAuthCode.java @@ -0,0 +1,77 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.locate; + +import java.security.Principal; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.eclipse.jetty.http.HttpStatus; +import org.onap.aaf.auth.env.AuthzTrans; +import org.onap.aaf.auth.locate.facade.LocateFacade; +import org.onap.aaf.cadi.Symm; +import org.onap.aaf.cadi.aaf.v2_0.AAFAuthn; +import org.onap.aaf.cadi.principal.BasicPrincipal; +import org.onap.aaf.cadi.principal.X509Principal; + +public class BasicAuthCode extends LocateCode { + private AAFAuthn authn; + + public BasicAuthCode(AAFAuthn authn, LocateFacade facade) { + super(facade, "AAF Basic Auth",true); + this.authn = authn; + } + + @Override + public void handle(AuthzTrans trans, HttpServletRequest req, HttpServletResponse resp) throws Exception { + Principal p = trans.getUserPrincipal(); + if(p == null) { + trans.error().log("Transaction not Authenticated... no Principal"); + } else if (p instanceof BasicPrincipal) { + // the idea is that if call is made with this credential, and it's a BasicPrincipal, it's ok + // otherwise, it wouldn't have gotten here. + resp.setStatus(HttpStatus.OK_200); + return; + } else if (p instanceof X509Principal) { + // Since X509Principal has priority, BasicAuth Info might be there, but not validated. + String ba; + if((ba=req.getHeader("Authorization"))!=null && ba.startsWith("Basic ")) { + ba = Symm.base64noSplit.decode(ba.substring(6)); + int colon = ba.indexOf(':'); + if(colon>=0) { + String err; + if((err=authn.validate(ba.substring(0, colon), ba.substring(colon+1),trans))==null) { + resp.setStatus(HttpStatus.OK_200); + } else { + trans.audit().log(ba.substring(0,colon),": ",err); + resp.setStatus(HttpStatus.UNAUTHORIZED_401); + } + return; + } + } + } + trans.checkpoint("Basic Auth Check Failed: This wasn't a Basic Auth Trans"); + // For Auth Security questions, we don't give any info to client on why failed + resp.setStatus(HttpStatus.FORBIDDEN_403); + } +} diff --git a/auth/auth-locate/src/main/java/org/onap/aaf/auth/locate/LocateCode.java b/auth/auth-locate/src/main/java/org/onap/aaf/auth/locate/LocateCode.java new file mode 100644 index 00000000..b1aa23cc --- /dev/null +++ b/auth/auth-locate/src/main/java/org/onap/aaf/auth/locate/LocateCode.java @@ -0,0 +1,44 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.locate; + +import org.onap.aaf.auth.env.AuthzTrans; +import org.onap.aaf.auth.locate.facade.LocateFacade; +import org.onap.aaf.auth.rserv.HttpCode; + +public abstract class LocateCode extends HttpCode implements Cloneable { + public boolean useJSON; + + public LocateCode(LocateFacade facade, String description, boolean useJSON, String ... roles) { + super(facade, description, roles); + this.useJSON = useJSON; + } + + public D clone(LocateFacade facade, boolean useJSON) throws Exception { + @SuppressWarnings("unchecked") + D d = (D)clone(); + d.useJSON = useJSON; + d.context = facade; + return d; + } + +} \ No newline at end of file diff --git a/auth/auth-locate/src/main/java/org/onap/aaf/auth/locate/api/API_AAFAccess.java b/auth/auth-locate/src/main/java/org/onap/aaf/auth/locate/api/API_AAFAccess.java new file mode 100644 index 00000000..9de92d14 --- /dev/null +++ b/auth/auth-locate/src/main/java/org/onap/aaf/auth/locate/api/API_AAFAccess.java @@ -0,0 +1,259 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.locate.api; + +import java.io.IOException; +import java.net.ConnectException; +import java.net.URI; +import java.security.Principal; + +import javax.servlet.ServletOutputStream; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.eclipse.jetty.http.HttpStatus; +import org.onap.aaf.auth.cache.Cache.Dated; +import org.onap.aaf.auth.env.AuthzTrans; +import org.onap.aaf.auth.layer.Result; +import org.onap.aaf.auth.locate.AAF_Locate; +import org.onap.aaf.auth.locate.BasicAuthCode; +import org.onap.aaf.auth.locate.LocateCode; +import org.onap.aaf.auth.locate.facade.LocateFacade; +import org.onap.aaf.auth.locate.mapper.Mapper.API; +import org.onap.aaf.auth.rserv.HttpMethods; +import org.onap.aaf.cadi.CadiException; +import org.onap.aaf.cadi.Locator; +import org.onap.aaf.cadi.Locator.Item; +import org.onap.aaf.cadi.LocatorException; +import org.onap.aaf.cadi.aaf.AAFPermission; +import org.onap.aaf.cadi.client.Future; +import org.onap.aaf.cadi.client.Rcli; +import org.onap.aaf.cadi.client.Retryable; +import org.onap.aaf.misc.env.APIException; +import org.onap.aaf.misc.env.Env; +import org.onap.aaf.misc.env.TimeTaken; + +public class API_AAFAccess { +// private static String service, version, envContext; + + private static final String GET_PERMS_BY_USER = "Get Perms by User"; + private static final String USER_HAS_PERM ="User Has Perm"; +// private static final String USER_IN_ROLE ="User Has Role"; + + /** + * Normal Init level APIs + * + * @param gwAPI + * @param facade + * @throws Exception + */ + public static void init(final AAF_Locate gwAPI, LocateFacade facade) throws Exception { + + + gwAPI.route(HttpMethods.GET,"/authz/perms/user/:user",API.VOID,new LocateCode(facade,GET_PERMS_BY_USER, true) { + @Override + public void handle(final AuthzTrans trans, final HttpServletRequest req, final HttpServletResponse resp) throws Exception { + TimeTaken tt = trans.start(GET_PERMS_BY_USER, Env.SUB); + try { + final String accept = req.getHeader("ACCEPT"); + final String user = pathParam(req,":user"); + if(!user.contains("@")) { + context.error(trans,resp,Result.ERR_BadData,"User [%s] must be fully qualified with domain",user); + return; + } + final String key = trans.user() + user + (accept!=null&&accept.contains("xml")?"-xml":"-json"); + TimeTaken tt2 = trans.start("Cache Lookup",Env.SUB); + Dated d; + try { + d = gwAPI.cacheUser.get(key); + } finally { + tt2.done(); + } + + if(d==null || d.data.isEmpty()) { + tt2 = trans.start("AAF Service Call",Env.REMOTE); + try { + gwAPI.clientAsUser(trans.getUserPrincipal(), new Retryable() { + @Override + public Void code(Rcli client) throws CadiException, ConnectException, APIException { + Future fp = client.read("/authz/perms/user/"+user,accept); + if(fp.get(5000)) { + gwAPI.cacheUser.put(key, new Dated(new User(fp.code(),fp.body()),gwAPI.expireIn)); + resp.setStatus(HttpStatus.OK_200); + ServletOutputStream sos; + try { + sos = resp.getOutputStream(); + sos.print(fp.value); + } catch (IOException e) { + throw new CadiException(e); + } + } else { + gwAPI.cacheUser.put(key, new Dated(new User(fp.code(),fp.body()),gwAPI.expireIn)); + context.error(trans,resp,fp.code(),fp.body()); + } + return null; + } + }); + } finally { + tt2.done(); + } + } else { + User u = (User)d.data.get(0); + resp.setStatus(u.code); + ServletOutputStream sos = resp.getOutputStream(); + sos.print(u.resp); + } + } finally { + tt.done(); + } + } + }); + + + gwAPI.route(gwAPI.env,HttpMethods.GET,"/authn/basicAuth",new BasicAuthCode(gwAPI.aafAuthn,facade) + ,"text/plain","*/*","*"); + + /** + * Query User Has Perm + */ + gwAPI.route(HttpMethods.GET,"/ask/:user/has/:type/:instance/:action",API.VOID,new LocateCode(facade,USER_HAS_PERM, true) { + @Override + public void handle(final AuthzTrans trans, final HttpServletRequest req, HttpServletResponse resp) throws Exception { + try { + resp.getOutputStream().print( + gwAPI.aafLurPerm.fish(new Principal() { + public String getName() { + return pathParam(req,":user"); + }; + }, new AAFPermission( + pathParam(req,":type"), + pathParam(req,":instance"), + pathParam(req,":action")))); + resp.setStatus(HttpStatus.OK_200); + } catch(Exception e) { + context.error(trans, resp, Result.ERR_General, e.getMessage()); + } + } + }); + + gwAPI.route(HttpMethods.GET,"/gui/:path*",API.VOID,new LocateCode(facade,"Short Access PROD GUI for AAF", true) { + @Override + public void handle(AuthzTrans trans, HttpServletRequest req, HttpServletResponse resp) throws Exception { + try { + redirect(trans, req, resp, context, + gwAPI.getGUILocator(), + "gui/"+pathParam(req,":path")); + } catch (LocatorException e) { + context.error(trans, resp, Result.ERR_BadData, e.getMessage()); + } catch (Exception e) { + context.error(trans, resp, Result.ERR_General, e.getMessage()); + } + } + }); + + gwAPI.route(HttpMethods.GET,"/aaf/:version/:path*",API.VOID,new LocateCode(facade,"Access PROD GUI for AAF", true) { + @Override + public void handle(AuthzTrans trans, HttpServletRequest req, HttpServletResponse resp) throws Exception { + try { + redirect(trans, req, resp, context, + gwAPI.getGUILocator(), + pathParam(req,":path")); + } catch (LocatorException e) { + context.error(trans, resp, Result.ERR_BadData, e.getMessage()); + } catch (Exception e) { + context.error(trans, resp, Result.ERR_General, e.getMessage()); + } + } + }); + } + + public static void initDefault(final AAF_Locate gwAPI, LocateFacade facade) throws Exception { + + /** + * "login" url + */ + gwAPI.route(HttpMethods.GET,"/login",API.VOID,new LocateCode(facade,"Access Login GUI for AAF", true) { + @Override + public void handle(AuthzTrans trans, HttpServletRequest req, HttpServletResponse resp) throws Exception { + try { + redirect(trans, req, resp, context, + gwAPI.getGUILocator(), + "login"); + } catch (LocatorException e) { + context.error(trans, resp, Result.ERR_BadData, e.getMessage()); + } catch (Exception e) { + context.error(trans, resp, Result.ERR_General, e.getMessage()); + } + } + }); + + + /** + * Default URL + */ + gwAPI.route(HttpMethods.GET,"/",API.VOID,new LocateCode(facade,"Access GUI for AAF", true) { + @Override + public void handle(AuthzTrans trans, HttpServletRequest req, HttpServletResponse resp) throws Exception { + try { + redirect(trans, req, resp, context, + gwAPI.getGUILocator(), + "gui/home"); + } catch (Exception e) { + context.error(trans, resp, Result.ERR_General, e.getMessage()); + } + } + }); + } + + private static void redirect(AuthzTrans trans, HttpServletRequest req, HttpServletResponse resp, LocateFacade context, Locator loc, String path) throws IOException { + try { + if(loc.hasItems()) { + Item item = loc.best(); + URI uri = loc.get(item); + StringBuilder redirectURL = new StringBuilder(uri.toString()); + redirectURL.append('/'); + redirectURL.append(path); + String str = req.getQueryString(); + if(str!=null) { + redirectURL.append('?'); + redirectURL.append(str); + } + trans.info().log("Redirect to",redirectURL); + resp.sendRedirect(redirectURL.toString()); + } else { + context.error(trans, resp, Result.err(Result.ERR_NotFound,"No Locations found for redirection")); + } + } catch (LocatorException e) { + context.error(trans, resp, Result.err(Result.ERR_NotFound,"No Endpoints found for %s",req.getPathInfo())); + } + } + + private static class User { + public final int code; + public final String resp; + + public User(int code, String resp) { + this.code = code; + this.resp = resp; + } + } +} diff --git a/auth/auth-locate/src/main/java/org/onap/aaf/auth/locate/api/API_Api.java b/auth/auth-locate/src/main/java/org/onap/aaf/auth/locate/api/API_Api.java new file mode 100644 index 00000000..8e3fab56 --- /dev/null +++ b/auth/auth-locate/src/main/java/org/onap/aaf/auth/locate/api/API_Api.java @@ -0,0 +1,97 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.locate.api; + +import static org.onap.aaf.auth.layer.Result.OK; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.eclipse.jetty.http.HttpStatus; +import org.onap.aaf.auth.env.AuthzTrans; +import org.onap.aaf.auth.layer.Result; +import org.onap.aaf.auth.locate.AAF_Locate; +import org.onap.aaf.auth.locate.LocateCode; +import org.onap.aaf.auth.locate.facade.LocateFacade; +import org.onap.aaf.auth.locate.mapper.Mapper.API; +import org.onap.aaf.auth.rserv.HttpMethods; +import org.onap.aaf.cadi.Symm; + +/** + * API Apis + * @author Jonathan + * + */ +public class API_Api { + /** + * Normal Init level APIs + * + * @param gwAPI + * @param facade + * @throws Exception + */ + public static void init(final AAF_Locate gwAPI, LocateFacade facade) throws Exception { + //////// + // Overall APIs + /////// + gwAPI.route(HttpMethods.GET,"/api",API.VOID,new LocateCode(facade,"Document API", true) { + @Override + public void handle(AuthzTrans trans, HttpServletRequest req, HttpServletResponse resp) throws Exception { + Result r = context.getAPI(trans,resp,gwAPI); + switch(r.status) { + case OK: + resp.setStatus(HttpStatus.OK_200); + break; + default: + context.error(trans,resp,r); + } + + } + }); + + //////// + // Overall Examples + /////// + gwAPI.route(HttpMethods.GET,"/api/example/*",API.VOID,new LocateCode(facade,"Document API", true) { + @Override + public void handle(AuthzTrans trans, HttpServletRequest req, HttpServletResponse resp) throws Exception { + String pathInfo = req.getPathInfo(); + int question = pathInfo.lastIndexOf('?'); + + pathInfo = pathInfo.substring(13, question<0?pathInfo.length():question);// IMPORTANT, this is size of "/api/example/" + String nameOrContextType=Symm.base64noSplit.decode(pathInfo); +// String param = req.getParameter("optional"); + Result r = context.getAPIExample(trans,resp,nameOrContextType, + question>=0 && "optional=true".equalsIgnoreCase(req.getPathInfo().substring(question+1)) + ); + switch(r.status) { + case OK: + resp.setStatus(HttpStatus.OK_200); + break; + default: + context.error(trans,resp,r); + } + } + }); + + } +} diff --git a/auth/auth-locate/src/main/java/org/onap/aaf/auth/locate/api/API_Find.java b/auth/auth-locate/src/main/java/org/onap/aaf/auth/locate/api/API_Find.java new file mode 100644 index 00000000..27bd8c3a --- /dev/null +++ b/auth/auth-locate/src/main/java/org/onap/aaf/auth/locate/api/API_Find.java @@ -0,0 +1,132 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.locate.api; + +import static org.onap.aaf.auth.layer.Result.OK; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.eclipse.jetty.http.HttpStatus; +import org.onap.aaf.auth.common.Define; +import org.onap.aaf.auth.env.AuthzTrans; +import org.onap.aaf.auth.layer.Result; +import org.onap.aaf.auth.locate.AAF_Locate; +import org.onap.aaf.auth.locate.LocateCode; +import org.onap.aaf.auth.locate.facade.LocateFacade; +import org.onap.aaf.auth.locate.mapper.Mapper.API; +import org.onap.aaf.auth.rserv.HttpMethods; +import org.onap.aaf.misc.env.util.Split; + +/** + * API Apis.. using Redirect for mechanism + * + * @author Jonathan + * + */ +public class API_Find { + /** + * Normal Init level APIs + * + * @param gwAPI + * @param facade + * @throws Exception + */ + public static void init(final AAF_Locate gwAPI, LocateFacade facade) throws Exception { + //////// + // Overall APIs + /////// + + final LocateCode locationInfo = new LocateCode(facade,"Location Information", true) { + @Override + public void handle(AuthzTrans trans, HttpServletRequest req, HttpServletResponse resp) throws Exception { + String service = pathParam(req, ":service"); + String version = pathParam(req, ":version"); + String other = pathParam(req, ":other"); + if(service.indexOf(':')>=0) { + String split[] = Split.split(':', service); + switch(split.length) { + case 3: + other=split[2]; + case 2: + version = split[1]; + service = split[0]; + } + } + service=Define.varReplace(service); + Result r = context.getEndpoints(trans,resp, + req.getPathInfo(), // use as Key + service,version,other + ); + switch(r.status) { + case OK: + resp.setStatus(HttpStatus.OK_200); + break; + default: + context.error(trans,resp,r); + } + } + }; + + gwAPI.route(HttpMethods.GET,"/locate/:service/:version",API.ENDPOINTS,locationInfo); + gwAPI.route(HttpMethods.GET,"/locate/:service/:version/:other",API.ENDPOINTS,locationInfo); + gwAPI.route(HttpMethods.GET,"/locate/:service",API.ENDPOINTS,locationInfo); + + + gwAPI.route(HttpMethods.GET,"/download/agent", API.VOID, new LocateCode(facade,"Redirect to latest Agent",false) { + @Override + public void handle(AuthzTrans arg0, HttpServletRequest arg1, HttpServletResponse arg2) throws Exception { + } + }); + + gwAPI.route(HttpMethods.PUT,"/registration",API.MGMT_ENDPOINTS,new LocateCode(facade,"Put Location Information", true) { + @Override + public void handle(AuthzTrans trans, HttpServletRequest req, HttpServletResponse resp) throws Exception { + Result r = context.putMgmtEndpoints(trans,req,resp); + switch(r.status) { + case OK: + resp.setStatus(HttpStatus.OK_200); + break; + default: + context.error(trans,resp,r); + } + + } + }); + + gwAPI.route(HttpMethods.DELETE,"/registration",API.MGMT_ENDPOINTS,new LocateCode(facade,"Remove Location Information", true) { + @Override + public void handle(AuthzTrans trans, HttpServletRequest req, HttpServletResponse resp) throws Exception { + Result r = context.removeMgmtEndpoints(trans,req,resp); + switch(r.status) { + case OK: + resp.setStatus(HttpStatus.OK_200); + break; + default: + context.error(trans,resp,r); + } + + } + }); + + } +} diff --git a/auth/auth-locate/src/main/java/org/onap/aaf/auth/locate/api/API_Proxy.java b/auth/auth-locate/src/main/java/org/onap/aaf/auth/locate/api/API_Proxy.java new file mode 100644 index 00000000..d2e4583c --- /dev/null +++ b/auth/auth-locate/src/main/java/org/onap/aaf/auth/locate/api/API_Proxy.java @@ -0,0 +1,163 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.locate.api; + +import java.net.ConnectException; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.eclipse.jetty.http.HttpStatus; +import org.onap.aaf.auth.env.AuthzTrans; +import org.onap.aaf.auth.locate.AAF_Locate; +import org.onap.aaf.auth.locate.BasicAuthCode; +import org.onap.aaf.auth.locate.LocateCode; +import org.onap.aaf.auth.locate.facade.LocateFacade; +import org.onap.aaf.auth.locate.mapper.Mapper.API; +import org.onap.aaf.auth.rserv.HttpMethods; +import org.onap.aaf.cadi.CadiException; +import org.onap.aaf.cadi.client.Future; +import org.onap.aaf.cadi.client.Rcli; +import org.onap.aaf.cadi.client.Retryable; +import org.onap.aaf.cadi.config.Config; +import org.onap.aaf.cadi.oauth.OAuth2Principal; +import org.onap.aaf.misc.env.APIException; +import org.onap.aaf.misc.env.Env; +import org.onap.aaf.misc.env.TimeTaken; + +/** + * API Apis.. using Redirect for mechanism + * + * @author Jonathan + * + */ +public class API_Proxy { + + /** + * Normal Init level APIs + * + * @param gwAPI + * @param facade + * @throws Exception + */ + public static void init(final AAF_Locate gwAPI, LocateFacade facade) throws Exception { + + String aafurl = gwAPI.access.getProperty(Config.AAF_URL,null); + if(aafurl==null) { + } else { + //////// + // Transferring APIs + // But DO NOT transfer BasicAuth case... wastes resources. + /////// + final BasicAuthCode bac = new BasicAuthCode(gwAPI.aafAuthn,facade); + + gwAPI.routeAll(HttpMethods.GET,"/proxy/:path*",API.VOID,new LocateCode(facade,"Proxy GET", true) { + @Override + public void handle(final AuthzTrans trans, final HttpServletRequest req, final HttpServletResponse resp) throws Exception { + if("/proxy/authn/basicAuth".equals(req.getPathInfo()) && !(req.getUserPrincipal() instanceof OAuth2Principal)) { + bac.handle(trans, req, resp); + } else { + TimeTaken tt = trans.start("Forward to AAF Service", Env.REMOTE); + try { + gwAPI.clientAsUser(trans.getUserPrincipal(), new Retryable() { + @Override + public Void code(Rcli client) throws CadiException, ConnectException, APIException { + Future ft = client.transfer(req,resp,pathParam(req, ":path"),HttpStatus.OK_200); + ft.get(10000); // Covers return codes and err messages + return null; + } + }); + + } catch (CadiException | APIException e) { + trans.error().log(e); + } finally { + tt.done(); + } + } + } + }); + + gwAPI.routeAll(HttpMethods.POST,"/proxy/:path*",API.VOID,new LocateCode(facade,"Proxy POST", true) { + @Override + public void handle(final AuthzTrans trans, final HttpServletRequest req, final HttpServletResponse resp) throws Exception { + TimeTaken tt = trans.start("Forward to AAF Service", Env.REMOTE); + try { + gwAPI.clientAsUser(trans.getUserPrincipal(), new Retryable() { + @Override + public Void code(Rcli client) throws CadiException, ConnectException, APIException { + Future ft = client.transfer(req,resp,pathParam(req, ":path"),HttpStatus.CREATED_201); + ft.get(10000); // Covers return codes and err messages + return null; + } + }); + } catch (CadiException | APIException e) { + trans.error().log(e); + } finally { + tt.done(); + } + } + }); + + gwAPI.routeAll(HttpMethods.PUT,"/proxy/:path*",API.VOID,new LocateCode(facade,"Proxy PUT", true) { + @Override + public void handle(final AuthzTrans trans, final HttpServletRequest req, final HttpServletResponse resp) throws Exception { + TimeTaken tt = trans.start("Forward to AAF Service", Env.REMOTE); + try { + gwAPI.clientAsUser(trans.getUserPrincipal(), new Retryable() { + @Override + public Void code(Rcli client) throws CadiException, ConnectException, APIException { + Future ft = client.transfer(req,resp,pathParam(req, ":path"),HttpStatus.OK_200); + ft.get(10000); // Covers return codes and err messages + return null; + } + }); + } catch (CadiException | APIException e) { + trans.error().log(e); + } finally { + tt.done(); + } + } + }); + + gwAPI.routeAll(HttpMethods.DELETE,"/proxy/:path*",API.VOID,new LocateCode(facade,"Proxy DELETE", true) { + @Override + public void handle(final AuthzTrans trans, final HttpServletRequest req, final HttpServletResponse resp) throws Exception { + TimeTaken tt = trans.start("Forward to AAF Service", Env.REMOTE); + try { + gwAPI.clientAsUser(trans.getUserPrincipal(), new Retryable() { + @Override + public Void code(Rcli client) throws CadiException, ConnectException, APIException { + Future ft = client.transfer(req,resp,pathParam(req, ":path"),HttpStatus.OK_200); + ft.get(10000); // Covers return codes and err messages + return null; + } + }); + } catch (CadiException | APIException e) { + trans.error().log(e); + } finally { + tt.done(); + } + } + }); + } + } +} diff --git a/auth/auth-locate/src/main/java/org/onap/aaf/auth/locate/facade/LocateFacade.java b/auth/auth-locate/src/main/java/org/onap/aaf/auth/locate/facade/LocateFacade.java new file mode 100644 index 00000000..817fcc58 --- /dev/null +++ b/auth/auth-locate/src/main/java/org/onap/aaf/auth/locate/facade/LocateFacade.java @@ -0,0 +1,106 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.locate.facade; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.onap.aaf.auth.env.AuthzTrans; +import org.onap.aaf.auth.layer.Result; +import org.onap.aaf.auth.rserv.RServlet; + + +/** + * + * @author Jonathan + * + */ +public interface LocateFacade { + +///////////////////// STANDARD ELEMENTS ////////////////// + /** + * @param trans + * @param response + * @param result + */ + void error(AuthzTrans trans, HttpServletResponse response, Result result); + + /** + * + * @param trans + * @param response + * @param status + */ + void error(AuthzTrans trans, HttpServletResponse response, int status, String msg, String ... detail); + + + /** + * + * @param trans + * @param resp + * @param rservlet + * @return + */ + public Result getAPI(AuthzTrans trans, HttpServletResponse resp, RServlet rservlet); + + /** + * + * @param trans + * @param resp + * @param typeCode + * @param optional + * @return + */ + public abstract Result getAPIExample(AuthzTrans trans, HttpServletResponse resp, String typeCode, boolean optional); + + /** + * + * @param trans + * @param resp + * @param service + * @param version + * @param other + * @param string + * @return + */ + public abstract Result getEndpoints(AuthzTrans trans, HttpServletResponse resp, String key, + String service, String version, String other); + + /** + * + * @param trans + * @param req + * @param resp + * @return + */ + public abstract Result putMgmtEndpoints(AuthzTrans trans, HttpServletRequest req, HttpServletResponse resp); + + /** + * + * @param trans + * @param req + * @param resp + * @return + */ + public abstract Result removeMgmtEndpoints(AuthzTrans trans, HttpServletRequest req, HttpServletResponse resp); + +} \ No newline at end of file diff --git a/auth/auth-locate/src/main/java/org/onap/aaf/auth/locate/facade/LocateFacadeFactory.java b/auth/auth-locate/src/main/java/org/onap/aaf/auth/locate/facade/LocateFacadeFactory.java new file mode 100644 index 00000000..ea20df5a --- /dev/null +++ b/auth/auth-locate/src/main/java/org/onap/aaf/auth/locate/facade/LocateFacadeFactory.java @@ -0,0 +1,48 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.locate.facade; + +import org.onap.aaf.auth.dao.cass.LocateDAO; +import org.onap.aaf.auth.env.AuthzEnv; +import org.onap.aaf.auth.env.AuthzTrans; +import org.onap.aaf.auth.locate.mapper.Mapper_1_0; +import org.onap.aaf.auth.locate.service.LocateServiceImpl; +import org.onap.aaf.misc.env.APIException; +import org.onap.aaf.misc.env.Data; + +import locate_local.v1_0.Error; +import locate_local.v1_0.InRequest; +import locate_local.v1_0.Out; + + +public class LocateFacadeFactory { + public static LocateFacade_1_0 v1_0(AuthzEnv env, LocateDAO locateDAO, AuthzTrans trans, Data.TYPE type) throws APIException { + return new LocateFacade_1_0( + env, + new LocateServiceImpl< + InRequest, + Out, + Error>(trans,locateDAO,new Mapper_1_0()), + type); + } + +} diff --git a/auth/auth-locate/src/main/java/org/onap/aaf/auth/locate/facade/LocateFacadeImpl.java b/auth/auth-locate/src/main/java/org/onap/aaf/auth/locate/facade/LocateFacadeImpl.java new file mode 100644 index 00000000..1ce9821f --- /dev/null +++ b/auth/auth-locate/src/main/java/org/onap/aaf/auth/locate/facade/LocateFacadeImpl.java @@ -0,0 +1,393 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.locate.facade; + + +import static org.onap.aaf.auth.layer.Result.ERR_ActionNotCompleted; +import static org.onap.aaf.auth.layer.Result.ERR_BadData; +import static org.onap.aaf.auth.layer.Result.ERR_ConflictAlreadyExists; +import static org.onap.aaf.auth.layer.Result.ERR_Denied; +import static org.onap.aaf.auth.layer.Result.ERR_NotFound; +import static org.onap.aaf.auth.layer.Result.ERR_NotImplemented; +import static org.onap.aaf.auth.layer.Result.ERR_Policy; +import static org.onap.aaf.auth.layer.Result.ERR_Security; +import static org.onap.aaf.auth.layer.Result.OK; + +import java.lang.reflect.Method; +import java.util.HashMap; +import java.util.Map; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.onap.aaf.auth.dao.cass.Status; +import org.onap.aaf.auth.env.AuthzEnv; +import org.onap.aaf.auth.env.AuthzTrans; +import org.onap.aaf.auth.layer.FacadeImpl; +import org.onap.aaf.auth.layer.Result; +import org.onap.aaf.auth.locate.mapper.Mapper; +import org.onap.aaf.auth.locate.mapper.Mapper.API; +import org.onap.aaf.auth.locate.service.LocateService; +import org.onap.aaf.auth.locate.service.LocateServiceImpl; +import org.onap.aaf.auth.rserv.RServlet; +import org.onap.aaf.auth.rserv.RouteReport; +import org.onap.aaf.auth.rserv.doc.ApiDoc; +import org.onap.aaf.cadi.aaf.client.Examples; +import org.onap.aaf.misc.env.APIException; +import org.onap.aaf.misc.env.Data; +import org.onap.aaf.misc.env.Env; +import org.onap.aaf.misc.env.TimeTaken; +import org.onap.aaf.misc.env.Data.TYPE; +import org.onap.aaf.misc.rosetta.env.RosettaDF; +import org.onap.aaf.misc.rosetta.env.RosettaData; + +import locate_local.v1_0.Api; + +/** + * AuthzFacade + * + * This Service Facade encapsulates the essence of the API Service can do, and provides + * a single created object for elements such as RosettaDF. + * + * The Responsibilities of this class are to: + * 1) Interact with the Service Implementation (which might be supported by various kinds of Backend Storage) + * 2) Validate incoming data (if applicable) + * 3) Convert the Service response into the right Format, and mark the Content Type + * a) In the future, we may support multiple Response Formats, aka JSON or XML, based on User Request. + * 4) Log Service info, warnings and exceptions as necessary + * 5) When asked by the API layer, this will create and write Error content to the OutputStream + * + * Note: This Class does NOT set the HTTP Status Code. That is up to the API layer, so that it can be + * clearly coordinated with the API Documentation + * + * @author Jonathan + * + */ +public abstract class LocateFacadeImpl extends FacadeImpl implements LocateFacade + { + private LocateService service; + + private final RosettaDF errDF; + private final RosettaDF apiDF; + private final RosettaDF epDF; + private final RosettaDF mepDF; + + + private static long cacheClear = 0L, emptyCheck=0L; + private final static Map epsCache = new HashMap(); // protected manually, in getEndpoints + + public LocateFacadeImpl(AuthzEnv env, LocateService service, Data.TYPE dataType) throws APIException { + this.service = service; + (errDF = env.newDataFactory(mapper().getClass(API.ERROR))).in(dataType).out(dataType); + (apiDF = env.newDataFactory(Api.class)).in(dataType).out(dataType); + (epDF = env.newDataFactory(mapper().getClass(API.ENDPOINTS))).in(dataType).out(dataType); + (mepDF = env.newDataFactory(mapper().getClass(API.MGMT_ENDPOINTS))).in(dataType).out(dataType); + } + + public Mapper mapper() { + return service.mapper(); + } + + /* (non-Javadoc) + * @see com.att.authz.facade.AuthzFacade#error(org.onap.aaf.auth.env.test.AuthzTrans, javax.servlet.http.HttpServletResponse, int) + * + * Note: Conforms to AT&T TSS RESTful Error Structure + */ + @Override + public void error(AuthzTrans trans, HttpServletResponse response, Result result) { + String msg = result.details==null?"":result.details.trim(); + String[] detail; + if(result.variables==null) { + detail = new String[1]; + } else { + int l = result.variables.length; + detail=new String[l+1]; + System.arraycopy(result.variables, 0, detail, 1, l); + } + error(trans, response, result.status,msg,detail); + } + + @Override + public void error(AuthzTrans trans, HttpServletResponse response, int status, String msg, String ... _detail) { + String[] detail = _detail; + if(detail.length==0) { + detail=new String[1]; + } + boolean hidemsg = false; + String msgId; + switch(status) { + case 202: + case ERR_ActionNotCompleted: + msgId = "SVC1202"; + detail[0] = "Accepted, Action not complete"; + response.setStatus(/*httpstatus=*/202); + break; + + case 403: + case ERR_Policy: + case ERR_Security: + case ERR_Denied: + msgId = "SVC1403"; + detail[0] = "Forbidden"; + response.setStatus(/*httpstatus=*/403); + break; + + case 404: + case ERR_NotFound: + msgId = "SVC1404"; + detail[0] = "Not Found"; + response.setStatus(/*httpstatus=*/404); + break; + + case 406: + case ERR_BadData: + msgId="SVC1406"; + detail[0] = "Not Acceptable"; + response.setStatus(/*httpstatus=*/406); + break; + + case 409: + case ERR_ConflictAlreadyExists: + msgId = "SVC1409"; + detail[0] = "Conflict Already Exists"; + response.setStatus(/*httpstatus=*/409); + break; + + case 501: + case ERR_NotImplemented: + msgId = "SVC1501"; + detail[0] = "Not Implemented"; + response.setStatus(/*httpstatus=*/501); + break; + + default: + msgId = "SVC1500"; + detail[0] = "General Service Error"; + response.setStatus(/*httpstatus=*/500); + hidemsg = true; + break; + } + + try { + StringBuilder holder = new StringBuilder(); + ERROR em = mapper().errorFromMessage(holder,msgId,msg,detail); + trans.checkpoint( + "ErrResp [" + + msgId + + "] " + + holder.toString(), + Env.ALWAYS); + if(hidemsg) { + holder.setLength(0); + em = mapper().errorFromMessage(holder, msgId, "Server had an issue processing this request"); + } + errDF.newData(trans).load(em).to(response.getOutputStream()); + + } catch (Exception e) { + trans.error().log(e,"unable to send response for",msg); + } + } + + /* (non-Javadoc) + * @see com.att.authz.facade.AuthzFacade#getAPI(org.onap.aaf.auth.env.test.AuthzTrans, javax.servlet.http.HttpServletResponse) + */ + public final static String API_REPORT = "apiReport"; + @Override + public Result getAPI(AuthzTrans trans, HttpServletResponse resp, RServlet rservlet) { + TimeTaken tt = trans.start(API_REPORT, Env.SUB); + try { + Api api = new Api(); + Api.Route ar; + Method[] meths = LocateServiceImpl.class.getDeclaredMethods(); + for(RouteReport rr : rservlet.routeReport()) { + api.getRoute().add(ar = new Api.Route()); + ar.setMeth(rr.meth.name()); + ar.setPath(rr.path); + ar.setDesc(rr.desc); + ar.getContentType().addAll(rr.contextTypes); + for(Method m : meths) { + ApiDoc ad; + if((ad = m.getAnnotation(ApiDoc.class))!=null && + rr.meth.equals(ad.method()) && + rr.path.equals(ad.path())) { + for(String param : ad.params()) { + ar.getParam().add(param); + } + for(String text : ad.text()) { + ar.getComments().add(text); + } + ar.setExpected(ad.expectedCode()); + for(int ec : ad.errorCodes()) { + ar.getExplicitErr().add(ec); + } + } + } + } + apiDF.newData(trans).load(api).to(resp.getOutputStream()); + setContentType(resp,apiDF.getOutType()); + return Result.ok(); + + } catch (Exception e) { + trans.error().log(e,IN,API_REPORT); + return Result.err(e); + } finally { + tt.done(); + } + } + + public final static String API_EXAMPLE = "apiExample"; + /* (non-Javadoc) + * @see com.att.authz.facade.AuthzFacade#getAPIExample(org.onap.aaf.auth.env.test.AuthzTrans, javax.servlet.http.HttpServletResponse, java.lang.String) + */ + @Override + public Result getAPIExample(AuthzTrans trans, HttpServletResponse resp, String nameOrContentType, boolean optional) { + TimeTaken tt = trans.start(API_EXAMPLE, Env.SUB); + try { + String content =Examples.print(apiDF.getEnv(), nameOrContentType, optional); + resp.getOutputStream().print(content); + setContentType(resp,content.contains(" getEndpoints(AuthzTrans trans, HttpServletResponse resp, String key, String service, String version, String other) { + TimeTaken tt = trans.start(GET_ENDPOINTS, Env.SUB); + try { + String output=null; + long temp=System.currentTimeMillis(); + synchronized(GET_ENDPOINTS) { + if(cacheClear reps = this.service.getEndPoints(trans,service,version,other); + if(reps.notOK()) { + return Result.err(reps); + } else { + output = epDF.newData(trans).load(reps.value).asString(); + synchronized(GET_ENDPOINTS) { + epsCache.put(key, output); + } + } + } + resp.getOutputStream().println(output); + setContentType(resp,epDF.getOutType()); + return Result.ok(); + } catch (Exception e) { + trans.error().log(e,IN,API_EXAMPLE); + return Result.err(Result.ERR_NotImplemented,e.getMessage()); + } finally { + tt.done(); + } + } + + private static final String PUT_MGMT_ENDPOINTS = "Put Mgmt Endpoints"; + /* (non-Javadoc) + * @see org.onap.aaf.auth.locate.facade.GwFacade#putMgmtEndpoints(org.onap.aaf.auth.env.test.AuthzTrans, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse) + */ + @Override + public Result putMgmtEndpoints(AuthzTrans trans, HttpServletRequest req, HttpServletResponse resp) { + TimeTaken tt = trans.start(PUT_MGMT_ENDPOINTS, Env.SUB|Env.ALWAYS); + try { + MGMT_ENDPOINTS rreq; + try { + RosettaData data = mepDF.newData().load(req.getInputStream()); + rreq = data.asObject(); + } catch(APIException e) { + trans.error().log("Invalid Input",IN,PUT_MGMT_ENDPOINTS); + return Result.err(Status.ERR_BadData,"Invalid Input"); + + } + Result rp = service.putMgmtEndPoints(trans, rreq); + switch(rp.status) { + case OK: + synchronized(GET_ENDPOINTS) { + cacheClear = 0L; + } + setContentType(resp,mepDF.getOutType()); + return Result.ok(); + default: + return rp; + } + } catch (Exception e) { + trans.error().log(e,IN,PUT_MGMT_ENDPOINTS); + return Result.err(e); + } finally { + tt.done(); + } + } + + private static final String DELETE_MGMT_ENDPOINTS = "Delete Mgmt Endpoints"; + /* (non-Javadoc) + * @see org.onap.aaf.auth.locate.facade.GwFacade#removeMgmtEndpoints(org.onap.aaf.auth.env.test.AuthzTrans, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse) + */ + @Override + public Result removeMgmtEndpoints(AuthzTrans trans, HttpServletRequest req, HttpServletResponse resp) { + TimeTaken tt = trans.start(DELETE_MGMT_ENDPOINTS, Env.SUB|Env.ALWAYS); + try { + MGMT_ENDPOINTS rreq; + try { + RosettaData data = mepDF.newData().load(req.getInputStream()); + rreq = data.asObject(); + } catch(APIException e) { + trans.error().log("Invalid Input",IN,DELETE_MGMT_ENDPOINTS); + return Result.err(Status.ERR_BadData,"Invalid Input"); + + } + Result rp = service.removeMgmtEndPoints(trans, rreq); + switch(rp.status) { + case OK: + synchronized(GET_ENDPOINTS) { + cacheClear = 0L; + } + setContentType(resp,mepDF.getOutType()); + return Result.ok(); + default: + return rp; + } + } catch (Exception e) { + trans.error().log(e,IN,DELETE_MGMT_ENDPOINTS); + return Result.err(e); + } finally { + tt.done(); + } + } + +} \ No newline at end of file diff --git a/auth/auth-locate/src/main/java/org/onap/aaf/auth/locate/facade/LocateFacade_1_0.java b/auth/auth-locate/src/main/java/org/onap/aaf/auth/locate/facade/LocateFacade_1_0.java new file mode 100644 index 00000000..e2d2c9f6 --- /dev/null +++ b/auth/auth-locate/src/main/java/org/onap/aaf/auth/locate/facade/LocateFacade_1_0.java @@ -0,0 +1,40 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.locate.facade; + +import org.onap.aaf.auth.env.AuthzEnv; +import org.onap.aaf.auth.locate.service.LocateService; +import org.onap.aaf.misc.env.APIException; +import org.onap.aaf.misc.env.Data; + +import locate.v1_0.Endpoints; +import locate.v1_0.MgmtEndpoints; +import locate_local.v1_0.InRequest; +import locate_local.v1_0.Out; +import locate_local.v1_0.Error; + +public class LocateFacade_1_0 extends LocateFacadeImpl +{ + public LocateFacade_1_0(AuthzEnv env, LocateService service, Data.TYPE type) throws APIException { + super(env, service, type); + } +} diff --git a/auth/auth-locate/src/main/java/org/onap/aaf/auth/locate/mapper/Mapper.java b/auth/auth-locate/src/main/java/org/onap/aaf/auth/locate/mapper/Mapper.java new file mode 100644 index 00000000..685d096f --- /dev/null +++ b/auth/auth-locate/src/main/java/org/onap/aaf/auth/locate/mapper/Mapper.java @@ -0,0 +1,41 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.locate.mapper; + +import java.util.List; + +import org.onap.aaf.auth.dao.cass.LocateDAO.Data; +import org.onap.aaf.auth.layer.Result; + +import locate.v1_0.MgmtEndpoint; + +public interface Mapper +{ + public enum API{IN_REQ,OUT,ENDPOINTS,MGMT_ENDPOINTS,ERROR,VOID}; + public Class getClass(API api); + public A newInstance(API api); + + public ERROR errorFromMessage(StringBuilder holder, String msgID, String text, String... detail); + public Result endpoints(Result> resultDB, String version, String other); + public Data locateData(MgmtEndpoint me); + +} diff --git a/auth/auth-locate/src/main/java/org/onap/aaf/auth/locate/mapper/Mapper_1_0.java b/auth/auth-locate/src/main/java/org/onap/aaf/auth/locate/mapper/Mapper_1_0.java new file mode 100644 index 00000000..50839b73 --- /dev/null +++ b/auth/auth-locate/src/main/java/org/onap/aaf/auth/locate/mapper/Mapper_1_0.java @@ -0,0 +1,150 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.locate.mapper; + +import java.util.List; + +import org.onap.aaf.auth.dao.cass.LocateDAO.Data; +import org.onap.aaf.auth.layer.Result; +import org.onap.aaf.cadi.util.Vars; +import org.onap.aaf.misc.env.util.Split; + +import locate.v1_0.Endpoint; +import locate.v1_0.Endpoints; +import locate.v1_0.MgmtEndpoint; +import locate.v1_0.MgmtEndpoints; +import locate_local.v1_0.Error; +import locate_local.v1_0.InRequest; +import locate_local.v1_0.Out; + +public class Mapper_1_0 implements Mapper { + + @Override + public Class getClass(API api) { + switch(api) { + case IN_REQ: return InRequest.class; + case OUT: return Out.class; + case ERROR: return Error.class; + case VOID: return Void.class; + case ENDPOINTS: return Endpoints.class; + case MGMT_ENDPOINTS: return MgmtEndpoints.class; + } + return null; + } + + @SuppressWarnings("unchecked") + @Override + public A newInstance(API api) { + switch(api) { + case IN_REQ: return (A) new InRequest(); + case OUT: return (A) new Out(); + case ERROR: return (A)new Error(); + case ENDPOINTS: return (A) new Endpoints(); + case MGMT_ENDPOINTS: return (A) new MgmtEndpoints(); + case VOID: return null; + } + return null; + } + + ////////////// Mapping Functions ///////////// + @Override + public locate_local.v1_0.Error errorFromMessage(StringBuilder holder, String msgID, String text,String... var) { + Error err = new Error(); + err.setMessageId(msgID); + // AT&T Restful Error Format requires numbers "%" placements + err.setText(Vars.convert(holder, text, var)); + for(String s : var) { + err.getVariables().add(s); + } + return err; + } + + /* (non-Javadoc) + * @see org.onap.aaf.auth.locate.mapper.Mapper#endpoints(org.onap.aaf.auth.layer.test.Result, java.lang.String, java.lang.String) + */ + @Override + public Result endpoints(Result> resultDB, String version, String other) { + if(resultDB.notOK()) { + return Result.err(resultDB); + } + int major=-1, minor=-1, patch=-1, pkg=-1; + if(version!=null) { + try { + String[] v = Split.split('.',version); + if(v.length>0) {major = Integer.parseInt(v[0]);} + if(v.length>1) {minor = Integer.parseInt(v[1]);} + if(v.length>2) {patch = Integer.parseInt(v[2]);} + if(v.length>3) {pkg = Integer.parseInt(v[3]);} + } catch (NumberFormatException e) { + return Result.err(Result.ERR_BadData,"Invalid Version String " + version); + } + } + Endpoints eps = new Endpoints(); + List leps = eps.getEndpoint(); + for(Data d : resultDB.value) { + if((major<0 || major==d.major) && + (minor<0 || minor<=d.minor) && + (patch<0 || patch==d.patch) && + (pkg<0 || pkg ==d.pkg)) { + Endpoint ep = new Endpoint(); + ep.setName(d.name); + ep.setHostname(d.hostname); + ep.setPort(d.port); + ep.setMajor(d.major); + ep.setMinor(d.minor); + ep.setPatch(d.patch); + ep.setPkg(d.pkg); + ep.setLatitude(d.latitude); + ep.setLongitude(d.longitude); + ep.setProtocol(d.protocol); + for(String s : d.subprotocol(false)) { + ep.getSubprotocol().add(s); + } + leps.add(ep); + } + } + return Result.ok(eps); + } + + /* (non-Javadoc) + * @see org.onap.aaf.auth.locate.mapper.Mapper#locateData(locate.v1_0.MgmtEndpoint) + */ + @Override + public Data locateData(MgmtEndpoint me) { + Data data = new Data(); + data.name = me.getName(); + data.port = me.getPort(); + data.hostname = me.getHostname(); + data.major = me.getMajor(); + data.minor = me.getMinor(); + data.patch = me.getPatch(); + data.pkg = me.getPkg(); + data.latitude = me.getLatitude(); + data.longitude = me.getLongitude(); + data.protocol = me.getProtocol(); + for(String s : me.getSubprotocol()) { + data.subprotocol(true).add(s); + } + return data; + } + +} \ No newline at end of file diff --git a/auth/auth-locate/src/main/java/org/onap/aaf/auth/locate/service/LocateService.java b/auth/auth-locate/src/main/java/org/onap/aaf/auth/locate/service/LocateService.java new file mode 100644 index 00000000..d2a37348 --- /dev/null +++ b/auth/auth-locate/src/main/java/org/onap/aaf/auth/locate/service/LocateService.java @@ -0,0 +1,33 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.locate.service; + +import org.onap.aaf.auth.env.AuthzTrans; +import org.onap.aaf.auth.layer.Result; +import org.onap.aaf.auth.locate.mapper.Mapper; + +public interface LocateService { + public Mapper mapper(); + public Result getEndPoints(AuthzTrans trans, String service, String version, String other); + public Result putMgmtEndPoints(AuthzTrans trans, MGMT_ENDPOINTS meps); + public Result removeMgmtEndPoints(AuthzTrans trans, MGMT_ENDPOINTS meps); +} diff --git a/auth/auth-locate/src/main/java/org/onap/aaf/auth/locate/service/LocateServiceImpl.java b/auth/auth-locate/src/main/java/org/onap/aaf/auth/locate/service/LocateServiceImpl.java new file mode 100644 index 00000000..d1a03cdc --- /dev/null +++ b/auth/auth-locate/src/main/java/org/onap/aaf/auth/locate/service/LocateServiceImpl.java @@ -0,0 +1,122 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.locate.service; + +import java.util.UUID; + +import org.onap.aaf.auth.dao.cass.LocateDAO; +import org.onap.aaf.auth.env.AuthzTrans; +import org.onap.aaf.auth.layer.Result; +import org.onap.aaf.auth.locate.mapper.Mapper; +import org.onap.aaf.auth.locate.validation.LocateValidator; +import org.onap.aaf.cadi.aaf.AAFPermission; +import org.onap.aaf.misc.env.APIException; + +import locate.v1_0.Endpoints; +import locate.v1_0.MgmtEndpoint; +import locate.v1_0.MgmtEndpoints; + +public class LocateServiceImpl + implements LocateService { + private Mapper mapper; + private LocateDAO locateDAO; + private boolean permToRegister; + + public LocateServiceImpl(AuthzTrans trans, LocateDAO locateDAO, Mapper mapper) throws APIException { + this.mapper = mapper; + this.locateDAO = locateDAO; + permToRegister = false; //TODO Setup a Configuration for this + } + + public Mapper mapper() {return mapper;} + + @Override + public Result getEndPoints(AuthzTrans trans, String service, String version, String other) { + return mapper.endpoints(locateDAO.readByName(trans, service), version, other); + } + + /* (non-Javadoc) + * @see org.onap.aaf.auth.locate.service.GwService#putMgmtEndPoints(org.onap.aaf.auth.env.test.AuthzTrans, java.lang.Object) + */ + @Override + public Result putMgmtEndPoints(AuthzTrans trans, MgmtEndpoints meps) { + LocateValidator v = new LocateValidator().mgmt_endpoints(meps, false); + if(v.err()) { + return Result.err(Result.ERR_BadData,v.errs()); + } + int count = 0; + for(MgmtEndpoint me : meps.getMgmtEndpoint()) { + if(permToRegister) { + int dot = me.getName().lastIndexOf('.'); // Note: Validator checks for NS for getName() + AAFPermission p = new AAFPermission(me.getName().substring(0,dot)+".locator",me.getName(),"write"); + if(trans.fish(p)) { + LocateDAO.Data data = mapper.locateData(me); + locateDAO.update(trans, data, true); + ++count; + } else { + return Result.err(Result.ERR_Denied,"May not register service (needs " + p.getKey() + ')'); + } + } else { //TODO if(MechID is part of Namespace) { + LocateDAO.Data data = mapper.locateData(me); + locateDAO.update(trans, data, true); + ++count; + } + } + if(count>0) { + return Result.ok(); + } else { + return Result.err(Result.ERR_NotFound, "No endpoints found"); + } + } + + /* (non-Javadoc) + * @see org.onap.aaf.auth.locate.service.GwService#removeMgmtEndPoints(org.onap.aaf.auth.env.test.AuthzTrans, java.lang.Object) + */ + @Override + public Result removeMgmtEndPoints(AuthzTrans trans, MgmtEndpoints meps) { + LocateValidator v = new LocateValidator().mgmt_endpoint_key(meps); + if(v.err()) { + return Result.err(Result.ERR_BadData,v.errs()); + } + int count = 0; + for(MgmtEndpoint me : meps.getMgmtEndpoint()) { + int dot = me.getName().lastIndexOf('.'); // Note: Validator checks for NS for getName() + AAFPermission p = new AAFPermission(me.getName().substring(0,dot)+".locator",me.getHostname(),"write"); + if(trans.fish(p)) { + LocateDAO.Data data = mapper.locateData(me); + data.port_key = UUID.randomUUID(); + locateDAO.delete(trans, data, false); + ++count; + } else { + return Result.err(Result.ERR_Denied,"May not register service (needs " + p.getKey() + ')'); + } + } + if(count>0) { + return Result.ok(); + } else { + return Result.err(Result.ERR_NotFound, "No endpoints found"); + } + } + + +//////////////// APIs /////////////////// +}; diff --git a/auth/auth-locate/src/main/java/org/onap/aaf/auth/locate/validation/LocateValidator.java b/auth/auth-locate/src/main/java/org/onap/aaf/auth/locate/validation/LocateValidator.java new file mode 100644 index 00000000..89157826 --- /dev/null +++ b/auth/auth-locate/src/main/java/org/onap/aaf/auth/locate/validation/LocateValidator.java @@ -0,0 +1,141 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.locate.validation; + +import org.onap.aaf.auth.validation.Validator; + +import locate.v1_0.Endpoint; +import locate.v1_0.Endpoints; +import locate.v1_0.MgmtEndpoint; +import locate.v1_0.MgmtEndpoint.SpecialPorts; +import locate.v1_0.MgmtEndpoints; + +/** + * Validator + * Consistently apply content rules for content (incoming) + * + * Note: We restrict content for usability in URLs (because RESTful service), and avoid + * issues with Regular Expressions, and other enabling technologies. + * @author Jonathan + * + */ +public class LocateValidator extends Validator { + private LocateValidator endpoint_key(Endpoint e) { + if(e==null) { + msg("Endpoint Data is null."); + } else { + nullOrBlank("Endpoint Name", e.getName()); + if(e.getName()!=null) { + int idx = e.getName().indexOf('.'); + if(idx<=0) { + msg("Endpoint Name must prefixed by Namespace"); + } + } + nullOrBlank("Endpoint Hostname", e.getHostname()); + intRange("Endpoint Port",e.getPort(),0,1000000); + } + return this; + } + + + public LocateValidator endpoint(Endpoint e) { + endpoint_key(e); + if(e!=null) { + intRange("Endpoint Major Version",e.getMajor(),0,2000); + intRange("Endpoint Minor Version",e.getMinor(),0,2000); + intRange("Endpoint Patch Version",e.getPatch(),0,2000); + intRange("Endpoint Pkg Version",e.getPkg(),0,2000); + floatRange("Endpoint Latitude",e.getLatitude(),-90f,90f); + floatRange("Endpoint Longitude",e.getLongitude(),-180f,180f); + nullOrBlank("Endpoint Protocol", e.getProtocol()); + for(String s : e.getSubprotocol()) { + nullOrBlank("Endpoint Subprotocol", s); + } + } + return this; + } + + public LocateValidator endpoints(Endpoints e, boolean emptyNotOK) { + if(e==null) { + msg("Endpoints Data is null."); + } else { + if(emptyNotOK && e.getEndpoint().size()==0) { + msg("Endpoints contains no endpoints"); + } else { + for(Endpoint ep : e.getEndpoint()) { + endpoint(ep); + } + } + } + return this; + } + + public LocateValidator mgmt_endpoint_key(MgmtEndpoints meps) { + if(meps==null) { + msg("MgmtEndpoints Data is null."); + } else { + for(MgmtEndpoint ep : meps.getMgmtEndpoint()) { + endpoint_key(ep); + } + } + return this; + } + + public LocateValidator mgmt_endpoints(MgmtEndpoints me, boolean emptyOK) { + if(me==null) { + msg("MgmtEndpoints Data is null."); + } else { + if(!emptyOK && me.getMgmtEndpoint().size()==0) { + msg("MgmtEndpoints contains no data"); + } else { + for(MgmtEndpoint ep : me.getMgmtEndpoint()) { + mgmt_endpoint(ep); + } + } + } + return this; + } + + private LocateValidator mgmt_endpoint(MgmtEndpoint ep) { + endpoint(ep); + for(SpecialPorts sp : ep.getSpecialPorts()) { + specialPorts(sp); + } + return this; + } + + private LocateValidator specialPorts(SpecialPorts sp) { + if(sp==null) { + msg("Special Ports is null."); + } else { + nullOrBlank("Special Port Name",sp.getName()); + nullOrBlank("Special Port Protocol",sp.getProtocol()); + intRange("Special Port",sp.getPort(),0,1000000); + + for(String s : sp.getProtocolVersions()) { + nullOrBlank("Special Port Protocol Version", s); + } + } + return this; + } + +} diff --git a/auth/auth-locate/src/main/xsd/locate_1_0.xsd b/auth/auth-locate/src/main/xsd/locate_1_0.xsd new file mode 100644 index 00000000..ea7b3cce --- /dev/null +++ b/auth/auth-locate/src/main/xsd/locate_1_0.xsd @@ -0,0 +1,122 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/auth/auth-oauth/.gitignore b/auth/auth-oauth/.gitignore new file mode 100644 index 00000000..418e5b3a --- /dev/null +++ b/auth/auth-oauth/.gitignore @@ -0,0 +1,5 @@ +/target/ +/.classpath +/bin/ +/.settings +/.project diff --git a/auth/auth-oauth/pom.xml b/auth/auth-oauth/pom.xml new file mode 100644 index 00000000..40ada58a --- /dev/null +++ b/auth/auth-oauth/pom.xml @@ -0,0 +1,108 @@ + + + + 4.0.0 + + org.onap.aaf.auth + parent + 2.1.0-SNAPSHOT + ../pom.xml + + + aaf-auth-oauth + AAF Auth OAuth Service + OAuth Component for AAF Auth + + + 25 + + + + + org.onap.aaf.auth + aaf-auth-core + + + + org.onap.aaf.auth + aaf-auth-cass + + + + org.onap.aaf.cadi + aaf-cadi-aaf + + + + + + + org.apache.maven.plugins + maven-jar-plugin + + + **/*.class + + + 2.3.1 + + + + org.apache.maven.plugins + maven-deploy-plugin + + true + + + + org.codehaus.mojo + appassembler-maven-plugin + + + + org.onap.aaf.auth.oauth.AAF_OAuth + oauth + + cadi_prop_files=${project.conf_dir}/org.osaaf.oauth.props + + + + + + + + + + + nexus + attarch-releases + http://mavencentral.it.att.com:8084/nexus/content/repositories/attarch-releases + + + nexus + attarch-snapshots + http://mavencentral.it.att.com:8084/nexus/content/repositories/attarch-snapshots + + + diff --git a/auth/auth-oauth/src/main/config/.gitignore b/auth/auth-oauth/src/main/config/.gitignore new file mode 100644 index 00000000..e53ef90a --- /dev/null +++ b/auth/auth-oauth/src/main/config/.gitignore @@ -0,0 +1 @@ +/log4j.properties diff --git a/auth/auth-oauth/src/main/config/oauth.props b/auth/auth-oauth/src/main/config/oauth.props new file mode 100644 index 00000000..cdd382d1 --- /dev/null +++ b/auth/auth-oauth/src/main/config/oauth.props @@ -0,0 +1,26 @@ +## +## AAF OAUTH2 API (authz-oauth) Properties +## + +# Standard AFT for this box +hostname=_HOSTNAME_ + +## DISCOVERY (DME2) Parameters on the Command Line +AFT_LATITUDE=_AFT_LATITUDE_ +AFT_LONGITUDE=_AFT_LONGITUDE_ +AFT_ENVIRONMENT=_AFT_ENVIRONMENT_ +DEPLOYED_VERSION=_ARTIFACT_VERSION_ + +## Pull in common/security properties + +cadi_prop_files=_COMMON_DIR_/com.att.aaf.common.props:_COMMON_DIR_/com.att.aaf.props + +##DME2 related parameters + +DMEServiceName=service=com.att.authz.oauth/version=_MAJOR_VER_._MINOR_VER_._PATCH_VER_/envContext=_ENV_CONTEXT_/routeOffer=_ROUTE_OFFER_ +AFT_DME2_PORT_RANGE=_AUTHZ_OAUTH_PORT_RANGE_ + + + + + diff --git a/auth/auth-oauth/src/main/java/org/onap/aaf/auth/oauth/AAF_OAuth.java b/auth/auth-oauth/src/main/java/org/onap/aaf/auth/oauth/AAF_OAuth.java new file mode 100644 index 00000000..1dac22fc --- /dev/null +++ b/auth/auth-oauth/src/main/java/org/onap/aaf/auth/oauth/AAF_OAuth.java @@ -0,0 +1,196 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + + +package org.onap.aaf.auth.oauth; + +import java.util.Map; + +import javax.servlet.Filter; + +import org.onap.aaf.auth.cache.Cache; +import org.onap.aaf.auth.cache.Cache.Dated; +import org.onap.aaf.auth.dao.CassAccess; +import org.onap.aaf.auth.dao.hl.Question; +import org.onap.aaf.auth.direct.DirectLocatorCreator; +import org.onap.aaf.auth.direct.DirectRegistrar; +import org.onap.aaf.auth.env.AuthzEnv; +import org.onap.aaf.auth.env.AuthzTrans; +import org.onap.aaf.auth.env.AuthzTransFilter; +import org.onap.aaf.auth.oauth.api.API_Token; +import org.onap.aaf.auth.oauth.facade.OAFacade; +import org.onap.aaf.auth.oauth.facade.OAFacade1_0; +import org.onap.aaf.auth.oauth.facade.OAFacadeFactory; +import org.onap.aaf.auth.oauth.mapper.Mapper.API; +import org.onap.aaf.auth.oauth.service.OAuthService; +import org.onap.aaf.auth.rserv.HttpCode; +import org.onap.aaf.auth.rserv.HttpMethods; +import org.onap.aaf.auth.server.AbsService; +import org.onap.aaf.auth.server.JettyServiceStarter; +import org.onap.aaf.cadi.CadiException; +import org.onap.aaf.cadi.LocatorException; +import org.onap.aaf.cadi.PropAccess; +import org.onap.aaf.cadi.aaf.v2_0.AAFAuthn; +import org.onap.aaf.cadi.aaf.v2_0.AAFLurPerm; +import org.onap.aaf.cadi.aaf.v2_0.AAFTrustChecker; +import org.onap.aaf.cadi.aaf.v2_0.AbsAAFLocator; +import org.onap.aaf.cadi.config.Config; +import org.onap.aaf.cadi.oauth.TokenMgr; +import org.onap.aaf.cadi.oauth.TokenMgr.TokenPermLoader; +import org.onap.aaf.cadi.register.Registrant; +import org.onap.aaf.misc.env.APIException; +import org.onap.aaf.misc.env.Env; +import org.onap.aaf.misc.env.Data.TYPE; + +import com.datastax.driver.core.Cluster; + +import aafoauth.v2_0.Introspect; + +public class AAF_OAuth extends AbsService { + private static final String DOT_OAUTH = ".oauth"; + public Map cacheUser; + public AAFAuthn aafAuthn; + public AAFLurPerm aafLurPerm; + private final OAuthService service; + private OAFacade1_0 facade1_0; + private final Question question; + private TokenPermLoader tpLoader; + private final Cluster cluster; + + /** + * Construct AuthzAPI with all the Context Supporting Routes that Authz needs + * + * @param env + * @param si + * @param dm + * @param decryptor + * @throws APIException + */ + public AAF_OAuth(final AuthzEnv env) throws Exception { + super(env.access(),env); + + String aaf_env = env.getProperty(Config.AAF_ENV); + if(aaf_env==null) { + throw new APIException("aaf_env needs to be set"); + } + + // Initialize Facade for all uses + AuthzTrans trans = env.newTrans(); + cluster = org.onap.aaf.auth.dao.CassAccess.cluster(env,null); + + aafLurPerm = aafCon().newLur(); + // Note: If you need both Authn and Authz construct the following: + aafAuthn = aafCon().newAuthn(aafLurPerm); + + // Start Background Processing + // Question question = + question = new Question(trans, cluster, CassAccess.KEYSPACE, true); + + // Have AAFLocator object Create DirectLocators for Location needs + AbsAAFLocator.setCreator(new DirectLocatorCreator(env, question.locateDAO)); + + + service = new OAuthService(env.access(),trans,question); + facade1_0 = OAFacadeFactory.v1_0(this, trans, service, TYPE.JSON); + StringBuilder sb = new StringBuilder(); + trans.auditTrail(2, sb); + trans.init().log(sb); + + API_Token.init(this, facade1_0); + } + + /** + * Setup XML and JSON implementations for each supported Version type + * + * We do this by taking the Code passed in and creating clones of these with the appropriate Facades and properties + * to do Versions and Content switches + * + */ + public void route(HttpMethods meth, String path, API api, HttpCode> code) throws Exception { + String version = "1.0"; + // Get Correct API Class from Mapper + Class respCls = facade1_0.mapper().getClass(api); + if(respCls==null) throw new Exception("Unknown class associated with " + api.getClass().getName() + ' ' + api.name()); + // setup Application API HTML ContentTypes for JSON and Route + String application = applicationJSON(respCls, version); + if(meth.equals(HttpMethods.POST)) { + route(env,meth,path,code,application,"application/json;version="+version,"application/x-www-form-urlencoded","*/*"); + } else { + route(env,meth,path,code,application,"application/json;version="+version,"*/*"); + } + } + + @Override + public Filter[] filters() throws CadiException, LocatorException { + try { + DirectOAuthTAF doat; + return new Filter[] {new AuthzTransFilter(env,aafCon(), + new AAFTrustChecker((Env)env), + doat = new DirectOAuthTAF(env,question,facade1_0), + doat.directUserPass() + )}; + } catch (NumberFormatException | APIException e) { + throw new CadiException("Invalid Property information", e); + } + } + + + @SuppressWarnings("unchecked") + @Override + public Registrant[] registrants(final int port) throws CadiException { + return new Registrant[] { + new DirectRegistrar(access,question.locateDAO,app_name,app_version,port), + new DirectRegistrar(access,question.locateDAO,app_name.replace(DOT_OAUTH, ".token"),app_version,port), + new DirectRegistrar(access,question.locateDAO,app_name.replace(DOT_OAUTH, ".introspect"),app_version,port) + + }; + } + + + @Override + public void destroy() { + Cache.stopTimer(); + if(service!=null) { + service.close(); + } + if(cluster!=null) { + cluster.close(); + } + super.destroy(); + } + + // For use in CADI ONLY + public TokenMgr.TokenPermLoader tpLoader() { + return tpLoader; + } + + public static void main(final String[] args) { + PropAccess propAccess = new PropAccess(args); + try { + AAF_OAuth service = new AAF_OAuth(new AuthzEnv(propAccess)); +// env.setLog4JNames("log4j.properties","authz","oauth","audit","init","trace"); + JettyServiceStarter jss = new JettyServiceStarter(service); + jss.start(); + } catch (Exception e) { + e.printStackTrace(); + } + } +} diff --git a/auth/auth-oauth/src/main/java/org/onap/aaf/auth/oauth/DirectOAuthTAF.java b/auth/auth-oauth/src/main/java/org/onap/aaf/auth/oauth/DirectOAuthTAF.java new file mode 100644 index 00000000..74c9947d --- /dev/null +++ b/auth/auth-oauth/src/main/java/org/onap/aaf/auth/oauth/DirectOAuthTAF.java @@ -0,0 +1,224 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.oauth; + +import java.io.IOException; +import java.security.GeneralSecurityException; +import java.security.NoSuchAlgorithmException; +import java.util.Map; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.onap.aaf.auth.dao.hl.Question; +import org.onap.aaf.auth.direct.DirectAAFUserPass; +import org.onap.aaf.auth.env.AuthzEnv; +import org.onap.aaf.auth.env.AuthzTrans; +import org.onap.aaf.auth.layer.Result; +import org.onap.aaf.auth.oauth.facade.DirectIntrospect; +import org.onap.aaf.auth.rserv.TransFilter; +import org.onap.aaf.cadi.CachedPrincipal; +import org.onap.aaf.cadi.CadiException; +import org.onap.aaf.cadi.Hash; +import org.onap.aaf.cadi.LocatorException; +import org.onap.aaf.cadi.PropAccess; +import org.onap.aaf.cadi.CachedPrincipal.Resp; +import org.onap.aaf.cadi.CredVal.Type; +import org.onap.aaf.cadi.Taf.LifeForm; +import org.onap.aaf.cadi.config.Config; +import org.onap.aaf.cadi.oauth.OAuth2HttpTafResp; +import org.onap.aaf.cadi.oauth.OAuth2Principal; +import org.onap.aaf.cadi.oauth.TokenClient; +import org.onap.aaf.cadi.oauth.TokenClientFactory; +import org.onap.aaf.cadi.oauth.TokenMgr; +import org.onap.aaf.cadi.oauth.TokenPerm; +import org.onap.aaf.cadi.oauth.TokenMgr.TokenPermLoader; +import org.onap.aaf.cadi.principal.OAuth2FormPrincipal; +import org.onap.aaf.cadi.taf.HttpTaf; +import org.onap.aaf.cadi.taf.TafResp; +import org.onap.aaf.cadi.taf.TafResp.RESP; +import org.onap.aaf.cadi.util.Split; +import org.onap.aaf.misc.env.APIException; + +import aafoauth.v2_0.Introspect; + +public class DirectOAuthTAF implements HttpTaf { + private PropAccess access; + private DirectIntrospect oaFacade; + private TokenMgr tkMgr; + private final DirectAAFUserPass directUserPass; + private TokenClient altIntrospectClient; + + public DirectOAuthTAF(AuthzEnv env, Question q, DirectIntrospect facade) throws APIException, CadiException { + access = env.access(); + oaFacade = facade; + tkMgr = TokenMgr.getInstance(access,"dbToken","dbIntrospect"); + String alt_url = access.getProperty(Config.AAF_ALT_OAUTH2_INTROSPECT_URL,null); + TokenClientFactory tcf; + if(alt_url!=null) { + try { + tcf = TokenClientFactory.instance(access); + String[] split = Split.split(',', alt_url); + int timeout = split.length>1?Integer.parseInt(split[1]):3000; + altIntrospectClient = tcf.newClient(split[0], timeout); + altIntrospectClient.client_creds(access.getProperty(Config.AAF_ALT_CLIENT_ID,null), + access.getProperty(Config.AAF_ALT_CLIENT_SECRET,null)); + } catch (GeneralSecurityException | IOException | LocatorException e) { + throw new CadiException(e); + } + } + + directUserPass = new DirectAAFUserPass(env,q); + } + + @Override + public TafResp validate(LifeForm reading, HttpServletRequest req, HttpServletResponse resp) { + String value; + String token; + if((value=req.getHeader("Authorization"))!=null && value.startsWith("Bearer ")) { + token = value.substring(7); + } else { + token = null; + } + + if("application/x-www-form-urlencoded".equals(req.getContentType())) { + Map map = req.getParameterMap(); + String client_id=null,client_secret=null,username=null,password=null; + for(Map.Entry es : map.entrySet()) { + switch(es.getKey()) { + case "client_id": + for(String s : es.getValue()) { + client_id=s; + } + break; + case "client_secret": + for(String s : es.getValue()) { + client_secret=s; + } + break; + case "username": + for(String s : es.getValue()) { + username=s; + } + break; + case "password": + for(String s : es.getValue()) { + password=s; + } + break; + case "token": + if(token!=null) { // Defined as both Bearer and Form Encoded - Error + return new OAuth2HttpTafResp(access, null, "Token Info found as both Bearer Token and Form Info", RESP.FAIL, resp, true); + } + for(String s : es.getValue()) { + token=s; + } + break; + // Ignore others + } + } + + if(client_id==null && client_secret==null) { + return new OAuth2HttpTafResp(access, null, "client_id and client_secret required", RESP.TRY_ANOTHER_TAF, resp, false); + } + + if(token==null) { // No Token to work with, use only Client_ID and Client_Secret + AuthzTrans trans = (AuthzTrans)req.getAttribute(TransFilter.TRANS_TAG); + + if(directUserPass.validate(client_id, Type.PASSWORD, client_secret.getBytes(), trans)) { + // Client_ID is valid + if(username==null) { // Validating just the Client_ID + return new OAuth2FormHttpTafResp(access,new OAuth2FormPrincipal(client_id,client_id),"OAuth client_id authenticated",RESP.IS_AUTHENTICATED,resp,false); + } else { + //TODO - Does a clientID need specific Authorization to pair authentication with user name? At the moment, no. + // username is ok. + if(password!=null) { + if(directUserPass.validate(username, Type.PASSWORD, password.getBytes(), trans)) { + return new OAuth2FormHttpTafResp(access,new OAuth2FormPrincipal(client_id, username),"OAuth username authenticated",RESP.IS_AUTHENTICATED,resp,false); + } else { + return new OAuth2HttpTafResp(access,null,"OAuth username " + username + " not authenticated ",RESP.FAIL,resp,true); + } + } else { // no Password + //TODO Check for Trust Permission, which requires looking up Perms? + return new OAuth2HttpTafResp(access,null,"OAuth username " + username + " not authenticated ",RESP.FAIL,resp,true); + } + } + } else { + return new OAuth2HttpTafResp(access,null,"OAuth client_id " + client_id + " not authenticated ",RESP.FAIL,resp,true); + } + } + } + + // OK, have only a Token to validate + if(token!=null) { + AuthzTrans trans = (AuthzTrans)req.getAttribute(TransFilter.TRANS_TAG); + + try { + Result ri = oaFacade.mappedIntrospect(trans, token); + if(ri.isOK()) { + TokenPerm tp = tkMgr.putIntrospect(ri.value, Hash.hashSHA256(token.getBytes())); + if(tp==null) { + return new OAuth2HttpTafResp(access, null, "TokenPerm persistence failure", RESP.FAIL, resp, false); + } else { + return new OAuth2HttpTafResp(access,new OAuth2Principal(tp,Hash.hashSHA256(token.getBytes())),"Token Authenticated",RESP.IS_AUTHENTICATED,resp,false); + } + } else { + return new OAuth2HttpTafResp(access, null, ri.errorString(), RESP.FAIL, resp, false); + } + } catch (APIException e) { + trans.error().log(e,"Error getting token"); + return new OAuth2HttpTafResp(access, null, "Error getting token: " + e.getMessage(), RESP.TRY_ANOTHER_TAF, resp, false); + } catch (NoSuchAlgorithmException e) { + return new OAuth2HttpTafResp(access, null, "Error in security algorithm: " + e.getMessage(), RESP.TRY_ANOTHER_TAF, resp, false); + } + } + return new OAuth2HttpTafResp(access, null, "No OAuth2 Credentials in OAuthForm", RESP.TRY_ANOTHER_TAF, resp, false); + } + + @Override + public Resp revalidate(CachedPrincipal prin, Object state) { + // TODO Auto-generated method stub + return null; + } + + class ServiceTPL implements TokenPermLoader { + private final AuthzTrans trans; + public ServiceTPL(AuthzTrans atrans) { + trans = atrans; + } + + @Override + public org.onap.aaf.cadi.client.Result load(String accessToken, byte[] cred) throws APIException, CadiException, LocatorException { + Result ri = oaFacade.mappedIntrospect(trans, accessToken); + if(ri.notOK()) { + //TODO what should the status mapping be? + return org.onap.aaf.cadi.client.Result.err(ri.status,ri.errorString()); + } + return org.onap.aaf.cadi.client.Result.ok(200,tkMgr.putIntrospect(ri.value, cred)); + } + } + + public DirectAAFUserPass directUserPass() { + return directUserPass; + } +} + diff --git a/auth/auth-oauth/src/main/java/org/onap/aaf/auth/oauth/OACode.java b/auth/auth-oauth/src/main/java/org/onap/aaf/auth/oauth/OACode.java new file mode 100644 index 00000000..f60c689b --- /dev/null +++ b/auth/auth-oauth/src/main/java/org/onap/aaf/auth/oauth/OACode.java @@ -0,0 +1,45 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.oauth; +import org.onap.aaf.auth.env.AuthzTrans; +import org.onap.aaf.auth.oauth.facade.OAFacade; +import org.onap.aaf.auth.rserv.HttpCode; + +import aafoauth.v2_0.Introspect; + +public abstract class OACode extends HttpCode> implements Cloneable { + public boolean useJSON; + + public OACode(OAFacade facade, String description, boolean useJSON, String ... roles) { + super(facade, description, roles); + this.useJSON = useJSON; + } + + public D clone(OAFacade facade, boolean useJSON) throws Exception { + @SuppressWarnings("unchecked") + D d = (D)clone(); + d.useJSON = useJSON; + d.context = facade; + return d; + } + +} \ No newline at end of file diff --git a/auth/auth-oauth/src/main/java/org/onap/aaf/auth/oauth/OAuth2Filter.java b/auth/auth-oauth/src/main/java/org/onap/aaf/auth/oauth/OAuth2Filter.java new file mode 100644 index 00000000..4442e36f --- /dev/null +++ b/auth/auth-oauth/src/main/java/org/onap/aaf/auth/oauth/OAuth2Filter.java @@ -0,0 +1,64 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.oauth; + +import java.io.IOException; +import java.security.Principal; + +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 org.onap.aaf.cadi.principal.BearerPrincipal; +import org.onap.aaf.cadi.util.Split; + +public class OAuth2Filter implements Filter { + + @Override + public void init(FilterConfig filterConfig) throws ServletException { + } + + @Override + public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { + HttpServletRequest hreq = (HttpServletRequest)request; + Principal p = hreq.getUserPrincipal(); + if(request.getContentType().equals("application/x-www-form-urlencoded")) { + + } else if(p instanceof BearerPrincipal) { + for(String authz : Split.splitTrim(';', hreq.getHeader("Authorization"))) { + if(authz.startsWith("Bearer ")) { + ((BearerPrincipal)p).setBearer(authz.substring(7)); + } + } + } + chain.doFilter(request, response); + } + + @Override + public void destroy() { + } + +} diff --git a/auth/auth-oauth/src/main/java/org/onap/aaf/auth/oauth/OAuth2FormHttpTafResp.java b/auth/auth-oauth/src/main/java/org/onap/aaf/auth/oauth/OAuth2FormHttpTafResp.java new file mode 100644 index 00000000..23d87e3e --- /dev/null +++ b/auth/auth-oauth/src/main/java/org/onap/aaf/auth/oauth/OAuth2FormHttpTafResp.java @@ -0,0 +1,65 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.oauth; + +import java.io.IOException; + +import javax.servlet.http.HttpServletResponse; + +import org.onap.aaf.cadi.Access; +import org.onap.aaf.cadi.principal.OAuth2FormPrincipal; +import org.onap.aaf.cadi.principal.TrustPrincipal; +import org.onap.aaf.cadi.taf.AbsTafResp; +import org.onap.aaf.cadi.taf.TafResp; + +public class OAuth2FormHttpTafResp extends AbsTafResp implements TafResp { + private HttpServletResponse httpResp; + private RESP status; + private final boolean wasFailed; + + public OAuth2FormHttpTafResp(Access access, OAuth2FormPrincipal principal, String desc, RESP status, HttpServletResponse resp, boolean wasFailed) { + super(access,principal, desc); + httpResp = resp; + this.status = status; + this.wasFailed = wasFailed; + } + + public OAuth2FormHttpTafResp(Access access, TrustPrincipal principal, String desc, RESP status,HttpServletResponse resp) { + super(access,principal, desc); + httpResp = resp; + this.status = status; + wasFailed = true; // if Trust Principal added, must be good + } + + public RESP authenticate() throws IOException { + httpResp.setStatus(401); // Unauthorized + return RESP.HTTP_REDIRECT_INVOKED; + } + + public RESP isAuthenticated() { + return status; + } + + public boolean isFailedAttempt() { + return wasFailed; + } +} diff --git a/auth/auth-oauth/src/main/java/org/onap/aaf/auth/oauth/api/API_Token.java b/auth/auth-oauth/src/main/java/org/onap/aaf/auth/oauth/api/API_Token.java new file mode 100644 index 00000000..f2836a7b --- /dev/null +++ b/auth/auth-oauth/src/main/java/org/onap/aaf/auth/oauth/api/API_Token.java @@ -0,0 +1,82 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.oauth.api; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.onap.aaf.auth.env.AuthzTrans; +import org.onap.aaf.auth.layer.Result; +import org.onap.aaf.auth.oauth.AAF_OAuth; +import org.onap.aaf.auth.oauth.OACode; +import org.onap.aaf.auth.oauth.facade.OAFacade; +import org.onap.aaf.auth.oauth.mapper.Mapper.API; +import org.onap.aaf.auth.rserv.HttpMethods; + +import aafoauth.v2_0.Introspect; + +/** + * API Apis + * @author Jonathan + * + */ +public class API_Token { + // Hide Public Constructor + private API_Token() {} + + /** + * Normal Init level APIs + * + * @param authzAPI + * @param facade + * @throws Exception + */ + public static void init(final AAF_OAuth authzAPI, OAFacade facade) throws Exception { + //////// + // Overall APIs + /////// + authzAPI.route(HttpMethods.POST,"/token",API.TOKEN,new OACode(facade,"OAuth Token", true) { + @Override + public void handle(AuthzTrans trans, HttpServletRequest req, HttpServletResponse resp) throws Exception { + Result r = context.createBearerToken(trans,req, resp); + if(r.isOK()) { + resp.setStatus(201/*HttpStatus.CREATED_201*/); + } else { + context.error(trans,resp,r); + } + } + }); + + authzAPI.route(HttpMethods.POST,"/introspect",API.INTROSPECT,new OACode(facade,"AAF Token Information", true) { + @Override + public void handle(AuthzTrans trans, HttpServletRequest req, HttpServletResponse resp) throws Exception { + Result r = context.introspect(trans,req, resp); + if(r.isOK()) { + resp.setStatus(200 /*HttpStatus.OK_200*/); + } else { + context.error(trans,resp,r); + } + } + }); + + } +} diff --git a/auth/auth-oauth/src/main/java/org/onap/aaf/auth/oauth/facade/DirectIntrospect.java b/auth/auth-oauth/src/main/java/org/onap/aaf/auth/oauth/facade/DirectIntrospect.java new file mode 100644 index 00000000..91423cef --- /dev/null +++ b/auth/auth-oauth/src/main/java/org/onap/aaf/auth/oauth/facade/DirectIntrospect.java @@ -0,0 +1,29 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.oauth.facade; + +import org.onap.aaf.auth.env.AuthzTrans; +import org.onap.aaf.auth.layer.Result; + +public interface DirectIntrospect { + Result mappedIntrospect(AuthzTrans trans, String token); +} diff --git a/auth/auth-oauth/src/main/java/org/onap/aaf/auth/oauth/facade/DirectIntrospectImpl.java b/auth/auth-oauth/src/main/java/org/onap/aaf/auth/oauth/facade/DirectIntrospectImpl.java new file mode 100644 index 00000000..91431c34 --- /dev/null +++ b/auth/auth-oauth/src/main/java/org/onap/aaf/auth/oauth/facade/DirectIntrospectImpl.java @@ -0,0 +1,57 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.oauth.facade; + +import org.onap.aaf.auth.dao.cass.OAuthTokenDAO; +import org.onap.aaf.auth.env.AuthzTrans; +import org.onap.aaf.auth.layer.FacadeImpl; +import org.onap.aaf.auth.layer.Result; +import org.onap.aaf.auth.oauth.mapper.MapperIntrospect; +import org.onap.aaf.auth.oauth.service.OAuthService; + +public class DirectIntrospectImpl extends FacadeImpl implements DirectIntrospect { + protected OAuthService service; + private MapperIntrospect mapper; + + public DirectIntrospectImpl(OAuthService service, MapperIntrospect mapper) { + this.service = service; + this.mapper = mapper; + } + + /* (non-Javadoc) + * @see org.onap.aaf.auth.oauth.facade.OAFacade#mappedIntrospect(org.onap.aaf.auth.env.test.AuthzTrans, java.lang.String) + */ + @Override + public Result mappedIntrospect(AuthzTrans trans, String token) { + Result rti; + Result rs = service.introspect(trans,token); + if(rs.notOK()) { + rti = Result.err(rs); + } else if(rs.isEmpty()) { + rti = Result.err(Result.ERR_NotFound,"No Token %s found",token); + } else { + rti = mapper.introspect(rs); + } + return rti; + } + +} diff --git a/auth/auth-oauth/src/main/java/org/onap/aaf/auth/oauth/facade/DirectOAFacadeImpl.java b/auth/auth-oauth/src/main/java/org/onap/aaf/auth/oauth/facade/DirectOAFacadeImpl.java new file mode 100644 index 00000000..f71f7c15 --- /dev/null +++ b/auth/auth-oauth/src/main/java/org/onap/aaf/auth/oauth/facade/DirectOAFacadeImpl.java @@ -0,0 +1,28 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.oauth.facade; + +import org.onap.aaf.auth.layer.FacadeImpl; + +public class DirectOAFacadeImpl extends FacadeImpl { + +} diff --git a/auth/auth-oauth/src/main/java/org/onap/aaf/auth/oauth/facade/OAFacade.java b/auth/auth-oauth/src/main/java/org/onap/aaf/auth/oauth/facade/OAFacade.java new file mode 100644 index 00000000..52ff38b7 --- /dev/null +++ b/auth/auth-oauth/src/main/java/org/onap/aaf/auth/oauth/facade/OAFacade.java @@ -0,0 +1,67 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.oauth.facade; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.onap.aaf.auth.env.AuthzTrans; +import org.onap.aaf.auth.layer.Result; +import org.onap.aaf.auth.oauth.service.OAuthService; + + +/** + * + * @author Jonathan + * + */ +public interface OAFacade { + +///////////////////// STANDARD ELEMENTS ////////////////// + /** + * @param trans + * @param response + * @param result + */ + public void error(AuthzTrans trans, HttpServletResponse response, Result result); + + /** + * + * @param trans + * @param response + * @param status + */ + public void error(AuthzTrans trans, HttpServletResponse response, int status, String msg, String ... detail); + + public Result createBearerToken(AuthzTrans trans, HttpServletRequest req, HttpServletResponse resp); + + public Result introspect(AuthzTrans trans, HttpServletRequest req, HttpServletResponse resp); + + public OAuthService service(); + + +///////////////////// STANDARD ELEMENTS ////////////////// + + + + +} \ No newline at end of file diff --git a/auth/auth-oauth/src/main/java/org/onap/aaf/auth/oauth/facade/OAFacade1_0.java b/auth/auth-oauth/src/main/java/org/onap/aaf/auth/oauth/facade/OAFacade1_0.java new file mode 100644 index 00000000..204a104a --- /dev/null +++ b/auth/auth-oauth/src/main/java/org/onap/aaf/auth/oauth/facade/OAFacade1_0.java @@ -0,0 +1,47 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.oauth.facade; + +import org.onap.aaf.auth.oauth.AAF_OAuth; +import org.onap.aaf.auth.oauth.mapper.Mapper; +import org.onap.aaf.auth.oauth.service.OAuthService; +import org.onap.aaf.misc.env.APIException; +import org.onap.aaf.misc.env.Data; + +import aaf.v2_0.Error; +import aafoauth.v2_0.Introspect; +import aafoauth.v2_0.Token; +import aafoauth.v2_0.TokenRequest; + +/** + * @author Jonathan + * + */ +public class OAFacade1_0 extends OAFacadeImpl { + public OAFacade1_0(AAF_OAuth api, + OAuthService service, + Mapper mapper, + Data.TYPE type) throws APIException { + super(api, service, mapper, type); + } + +} diff --git a/auth/auth-oauth/src/main/java/org/onap/aaf/auth/oauth/facade/OAFacadeFactory.java b/auth/auth-oauth/src/main/java/org/onap/aaf/auth/oauth/facade/OAFacadeFactory.java new file mode 100644 index 00000000..ff586007 --- /dev/null +++ b/auth/auth-oauth/src/main/java/org/onap/aaf/auth/oauth/facade/OAFacadeFactory.java @@ -0,0 +1,47 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.oauth.facade; + +import org.onap.aaf.auth.env.AuthzTrans; +import org.onap.aaf.auth.oauth.AAF_OAuth; +import org.onap.aaf.auth.oauth.mapper.Mapper1_0; +import org.onap.aaf.auth.oauth.mapper.MapperIntrospect1_0; +import org.onap.aaf.auth.oauth.service.OAuthService; +import org.onap.aaf.misc.env.APIException; +import org.onap.aaf.misc.env.Data; + +import aafoauth.v2_0.Introspect; + + +public class OAFacadeFactory { + public static OAFacade1_0 v1_0(AAF_OAuth certman, AuthzTrans trans, OAuthService service, Data.TYPE type) throws APIException { + return new OAFacade1_0( + certman, + service, + new Mapper1_0(), + type); + } + + public static DirectIntrospect directV1_0(OAuthService service) { + return new DirectIntrospectImpl(service, new MapperIntrospect1_0()); + } +} diff --git a/auth/auth-oauth/src/main/java/org/onap/aaf/auth/oauth/facade/OAFacadeImpl.java b/auth/auth-oauth/src/main/java/org/onap/aaf/auth/oauth/facade/OAFacadeImpl.java new file mode 100644 index 00000000..ee35b8bf --- /dev/null +++ b/auth/auth-oauth/src/main/java/org/onap/aaf/auth/oauth/facade/OAFacadeImpl.java @@ -0,0 +1,333 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.oauth.facade; + +import static org.onap.aaf.auth.layer.Result.ERR_ActionNotCompleted; +import static org.onap.aaf.auth.layer.Result.ERR_BadData; +import static org.onap.aaf.auth.layer.Result.ERR_ConflictAlreadyExists; +import static org.onap.aaf.auth.layer.Result.ERR_Denied; +import static org.onap.aaf.auth.layer.Result.ERR_NotFound; +import static org.onap.aaf.auth.layer.Result.ERR_NotImplemented; +import static org.onap.aaf.auth.layer.Result.ERR_Policy; +import static org.onap.aaf.auth.layer.Result.ERR_Security; +import static org.onap.aaf.auth.layer.Result.OK; + +import java.security.Principal; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.onap.aaf.auth.dao.cass.OAuthTokenDAO; +import org.onap.aaf.auth.dao.cass.Status; +import org.onap.aaf.auth.dao.hl.Question; +import org.onap.aaf.auth.env.AuthzEnv; +import org.onap.aaf.auth.env.AuthzTrans; +import org.onap.aaf.auth.layer.Result; +import org.onap.aaf.auth.oauth.AAF_OAuth; +import org.onap.aaf.auth.oauth.mapper.Mapper; +import org.onap.aaf.auth.oauth.mapper.Mapper.API; +import org.onap.aaf.auth.oauth.service.OAuthService; +import org.onap.aaf.auth.oauth.service.OAuthService.GRANT_TYPE; +import org.onap.aaf.cadi.client.Holder; +import org.onap.aaf.cadi.oauth.OAuth2Principal; +import org.onap.aaf.cadi.principal.OAuth2FormPrincipal; +import org.onap.aaf.misc.env.APIException; +import org.onap.aaf.misc.env.Data; +import org.onap.aaf.misc.env.Env; +import org.onap.aaf.misc.env.TimeTaken; +import org.onap.aaf.misc.rosetta.env.RosettaDF; +import org.onap.aaf.misc.rosetta.env.RosettaData; + +import aaf.v2_0.Perms; + +/** + * AuthzFacade + * + * This Service Facade encapsulates the essence of the API Service can do, and provides + * a single created object for elements such as RosettaDF. + * + * The Responsibilities of this class are to: + * 1) Interact with the Service Implementation (which might be supported by various kinds of Backend Storage) + * 2) Validate incoming data (if applicable) + * 3) Convert the Service response into the right Format, and mark the Content Type + * a) In the future, we may support multiple Response Formats, aka JSON or XML, based on User Request. + * 4) Log Service info, warnings and exceptions as necessary + * 5) When asked by the API layer, this will create and write Error content to the OutputStream + * + * Note: This Class does NOT set the HTTP Status Code. That is up to the API layer, so that it can be + * clearly coordinated with the API Documentation + * + * @author Jonathan + * + */ +public abstract class OAFacadeImpl + extends DirectIntrospectImpl implements OAFacade { + private static final String INVALID_INPUT = "Invalid Input"; + private final RosettaDF tokenDF; + private final RosettaDF tokenReqDF; + private final RosettaDF introspectDF; + private final RosettaDF errDF; + public final RosettaDF permsDF; + private final Mapper mapper; + + public OAFacadeImpl(AAF_OAuth api, + OAuthService service, + Mapper mapper, + Data.TYPE dataType) throws APIException { + super(service, mapper); + this.mapper = mapper; + AuthzEnv env = api.env; + (tokenReqDF = env.newDataFactory(mapper.getClass(API.TOKEN_REQ))).in(dataType).out(dataType); + (tokenDF = env.newDataFactory(mapper.getClass(API.TOKEN))).in(dataType).out(dataType); + (introspectDF = env.newDataFactory(mapper.getClass(API.INTROSPECT))).in(dataType).out(dataType); + (permsDF = env.newDataFactory(Perms.class)).in(dataType).out(dataType); + (errDF = env.newDataFactory(mapper.getClass(API.ERROR))).in(dataType).out(dataType); + } + + /////////////////////////// + // Tokens + /////////////////////////// + public static final String CREATE_TOKEN = "createToken"; + public static final String INTROSPECT = "introspect"; + + /* (non-Javadoc) + * @see org.onap.aaf.auth.oauth.facade.OAFacade#getToken(org.onap.aaf.auth.env.test.AuthzTrans, javax.servlet.http.HttpServletResponse, org.onap.aaf.auth.oauth.service.OAuthAPI) + */ + @Override + public Result createBearerToken(AuthzTrans trans, HttpServletRequest req, HttpServletResponse resp) { + TimeTaken tt = trans.start(CREATE_TOKEN, Env.SUB|Env.ALWAYS); + try { + TOKEN_REQ request; + try { + request = mapper.tokenReqFromParams(req); + if(request==null) { + Data rd = tokenReqDF.newData().load(req.getInputStream()); + if(Question.willSpecialLog(trans, trans.user())) { + Question.logEncryptTrace(trans,rd.asString()); + } + request = rd.asObject(); + } + } catch(APIException e) { + trans.error().log(INVALID_INPUT,IN,CREATE_TOKEN); + return Result.err(Status.ERR_BadData,INVALID_INPUT); + } + + // Already validated for Oauth2FormPrincipal +// Result rv = service.validate(trans,mapper.credsFromReq(request)); +// if(rv.notOK()) { +// return rv; +// } + Holder hgt = new Holder(GRANT_TYPE.unknown); + Result rs = service.createToken(trans,req,mapper.clientTokenReq(request,hgt),hgt); + Result rp; + if(rs.isOKhasData()) { + rp = mapper.tokenFromData(rs); + } else { + rp = Result.err(rs); + } + switch(rp.status) { + case OK: + RosettaData data = tokenDF.newData(trans).load(rp.value); + if(Question.willSpecialLog(trans, trans.user())) { + Question.logEncryptTrace(trans,data.asString()); + } + data.to(resp.getOutputStream()); + resp.getOutputStream().print('\n'); + setContentType(resp,tokenDF.getOutType()); + return Result.ok(); + default: + return Result.err(rp); + } + } catch (Exception e) { + trans.error().log(e,IN,CREATE_TOKEN); + return Result.err(e); + } finally { + tt.done(); + } + + } + +/* (non-Javadoc) + * @see org.onap.aaf.auth.oauth.facade.OAFacade#Introspect(org.onap.aaf.auth.env.test.AuthzTrans, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse) + */ + @Override + public Result introspect(AuthzTrans trans, HttpServletRequest req, HttpServletResponse resp) { + TimeTaken tt = trans.start(INTROSPECT, Env.SUB|Env.ALWAYS); + try { + Principal p = req.getUserPrincipal(); + String token=null; + if(p != null) { + if(p instanceof OAuth2Principal) { + RosettaData data = introspectDF.newData(trans).load(mapper.fromPrincipal((OAuth2Principal)p)); + if(Question.willSpecialLog(trans, trans.user())) { + Question.logEncryptTrace(trans,data.asString()); + } + data.to(resp.getOutputStream()); + resp.getOutputStream().print('\n'); + setContentType(resp,tokenDF.getOutType()); + return Result.ok(); + } else if(p instanceof OAuth2FormPrincipal) { + token = req.getParameter("token"); + } + } + + if(token==null) { + token = req.getParameter("access_token"); + if(token==null || token.isEmpty()) { + token = req.getHeader("Authorization"); + if(token != null && token.startsWith("Bearer ")) { + token = token.substring(7); + } else { + token = req.getParameter("token"); + if(token==null) { + return Result.err(Result.ERR_Security,"token is required"); + } + } + } + } + + Result rti = mappedIntrospect(trans,token); + switch(rti.status) { + case OK: + RosettaData data = introspectDF.newData(trans).load(rti.value); + if(Question.willSpecialLog(trans, trans.user())) { + Question.logEncryptTrace(trans,data.asString()); + } + data.to(resp.getOutputStream()); + resp.getOutputStream().print('\n'); + setContentType(resp,tokenDF.getOutType()); + return Result.ok(); + default: + return Result.err(rti); + } + } catch (Exception e) { + trans.error().log(e,IN,INTROSPECT); + return Result.err(e); + } finally { + tt.done(); + } + } + + + /* (non-Javadoc) + * @see com.att.authz.facade.AuthzFacade#error(org.onap.aaf.auth.env.test.AuthzTrans, javax.servlet.http.HttpServletResponse, int) + * + * Note: Conforms to AT&T TSS RESTful Error Structure + */ + @Override + public void error(AuthzTrans trans, HttpServletResponse response, Result result) { + error(trans, response, result.status, + result.details==null?"":result.details.trim(), + result.variables==null?new String[0]:result.variables); + } + + @Override + public void error(AuthzTrans trans, HttpServletResponse response, int status, final String _msg, final String ... _detail) { + String msgId; + String prefix; + boolean hidemsg=false; + switch(status) { + case 202: + case ERR_ActionNotCompleted: + msgId = "SVC1202"; + prefix = "Accepted, Action not complete"; + response.setStatus(/*httpstatus=*/202); + break; + + case 403: + case ERR_Policy: + case ERR_Security: + case ERR_Denied: + msgId = "SVC1403"; + prefix = "Forbidden"; + response.setStatus(/*httpstatus=*/403); + break; + + case 404: + case ERR_NotFound: + msgId = "SVC1404"; + prefix = "Not Found"; + response.setStatus(/*httpstatus=*/404); + break; + + case 406: + case ERR_BadData: + msgId="SVC1406"; + prefix = "Not Acceptable"; + response.setStatus(/*httpstatus=*/406); + break; + + case 409: + case ERR_ConflictAlreadyExists: + msgId = "SVC1409"; + prefix = "Conflict Already Exists"; + response.setStatus(/*httpstatus=*/409); + break; + + case 501: + case ERR_NotImplemented: + msgId = "SVC1501"; + prefix = "Not Implemented"; + response.setStatus(/*httpstatus=*/501); + break; + + + default: + msgId = "SVC1500"; + prefix = "General Service Error"; + response.setStatus(/*httpstatus=*/500); + hidemsg=true; + break; + } + + try { + StringBuilder holder = new StringBuilder(); + ERROR em = mapper.errorFromMessage(holder, msgId,prefix + ": " + _msg,_detail); + trans.checkpoint( + "ErrResp [" + + msgId + + "] " + + holder.toString(), + Env.ALWAYS); + if(hidemsg) { + holder.setLength(0); + em = mapper.errorFromMessage(holder, msgId, "Server had an issue processing this request"); + } + errDF.newData(trans).load(em).to(response.getOutputStream()); + + } catch (Exception e) { + trans.error().log(e,"unable to send response for",_msg); + } + } + + public Mapper mapper() { + return mapper; + } + + /* (non-Javadoc) + * @see org.onap.aaf.auth.oauth.facade.OAFacade#service() + */ + @Override + public OAuthService service() { + return service; + } +} \ No newline at end of file diff --git a/auth/auth-oauth/src/main/java/org/onap/aaf/auth/oauth/mapper/Mapper.java b/auth/auth-oauth/src/main/java/org/onap/aaf/auth/oauth/mapper/Mapper.java new file mode 100644 index 00000000..55100e21 --- /dev/null +++ b/auth/auth-oauth/src/main/java/org/onap/aaf/auth/oauth/mapper/Mapper.java @@ -0,0 +1,47 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.oauth.mapper; + +import javax.servlet.http.HttpServletRequest; + +import org.onap.aaf.auth.dao.cass.OAuthTokenDAO; +import org.onap.aaf.auth.layer.Result; +import org.onap.aaf.auth.oauth.service.OCreds; +import org.onap.aaf.auth.oauth.service.OAuthService.GRANT_TYPE; +import org.onap.aaf.cadi.client.Holder; +import org.onap.aaf.cadi.oauth.OAuth2Principal; + +public interface Mapper extends MapperIntrospect +{ + public enum API{TOKEN_REQ, TOKEN,INTROSPECT, ERROR,VOID}; + + public Class getClass(API api); + public A newInstance(API api); + + public ERROR errorFromMessage(StringBuilder holder, String msgID, String text, String... detail); + public TOKEN_REQ tokenReqFromParams(HttpServletRequest req); + public OCreds credsFromReq(TOKEN_REQ tokReq); + + public OAuthTokenDAO.Data clientTokenReq(TOKEN_REQ tokReq, Holder hgt); + public Result tokenFromData(Result rs); + public INTROSPECT fromPrincipal(OAuth2Principal p); +} diff --git a/auth/auth-oauth/src/main/java/org/onap/aaf/auth/oauth/mapper/Mapper1_0.java b/auth/auth-oauth/src/main/java/org/onap/aaf/auth/oauth/mapper/Mapper1_0.java new file mode 100644 index 00000000..ee4237c8 --- /dev/null +++ b/auth/auth-oauth/src/main/java/org/onap/aaf/auth/oauth/mapper/Mapper1_0.java @@ -0,0 +1,225 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.oauth.mapper; + +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; + +import javax.servlet.http.HttpServletRequest; + +import org.onap.aaf.auth.dao.cass.OAuthTokenDAO; +import org.onap.aaf.auth.dao.cass.OAuthTokenDAO.Data; +import org.onap.aaf.auth.layer.Result; +import org.onap.aaf.auth.oauth.service.OAuthService; +import org.onap.aaf.auth.oauth.service.OCreds; +import org.onap.aaf.auth.oauth.service.OAuthService.CLIENT_TYPE; +import org.onap.aaf.auth.oauth.service.OAuthService.GRANT_TYPE; +import org.onap.aaf.cadi.client.Holder; +import org.onap.aaf.cadi.oauth.OAuth2Principal; +import org.onap.aaf.cadi.util.Vars; +import org.onap.aaf.misc.env.util.Split; + +import aaf.v2_0.Error; +import aafoauth.v2_0.Introspect; +import aafoauth.v2_0.Token; +import aafoauth.v2_0.TokenRequest; + + +public class Mapper1_0 extends MapperIntrospect1_0 implements Mapper { + @Override + public Class getClass(API api) { + switch(api) { + case TOKEN_REQ: return TokenRequest.class; + case TOKEN: return Token.class; + case INTROSPECT: return Introspect.class; + case ERROR: return Error.class; + case VOID: return Void.class; + } + return null; + } + + @SuppressWarnings("unchecked") + @Override + public A newInstance(API api) { + switch(api) { + case TOKEN_REQ: return (A)new TokenRequest(); + case TOKEN: return (A)new Token(); + case INTROSPECT: return (A)new Introspect(); + case ERROR: return (A)new Error(); + case VOID: return null; + } + return null; + } + + ////////////// Mapping Functions ///////////// + @Override + public Error errorFromMessage(StringBuilder holder, String msgID, String text, String... var) { + Error err = new Error(); + err.setMessageId(msgID); + // AT&T Restful Error Format requires numbers "%" placements + err.setText(Vars.convert(holder, text, var)); + for(String s : var) { + err.getVariables().add(s); + } + return err; + } + + @Override + public TokenRequest tokenReqFromParams(HttpServletRequest req) { + TokenRequest tr = new TokenRequest(); + boolean data = false; + @SuppressWarnings("unchecked") + Map map = req.getParameterMap(); + for(Entry es : map.entrySet()) { + switch(es.getKey()) { + case "client_id": + if(es.getValue().length==1) { + tr.setClientId(es.getValue()[0]); + data = true; + } + break; + case "client_secret": + if(es.getValue().length==1) { + tr.setClientSecret(es.getValue()[0]); + data = true; + } + break; + case "username": + if(es.getValue().length==1) { + tr.setUsername(es.getValue()[0]); + data = true; + } + break; + case "password": + if(es.getValue().length==1) { + tr.setPassword(es.getValue()[0]); + data = true; + } + break; + case "scope": + if(es.getValue().length==1) { + tr.setScope(es.getValue()[0]); + data = true; + } + break; + case "grant_type": + if(es.getValue().length==1) { + tr.setGrantType(es.getValue()[0]); + data = true; + } + break; + case "refresh_token": + if(es.getValue().length==1) { + tr.setRefreshToken(es.getValue()[0]); + data = true; + } + break; + + } + } + return data?tr:null; + } + + + + /* (non-Javadoc) + * @see org.onap.aaf.auth.oauth.mapper.Mapper#credsFromReq(javax.servlet.http.HttpServletRequest) + */ + @Override + public OCreds credsFromReq(TokenRequest tokReq) { + return new OCreds(tokReq.getClientId(),tokReq.getClientSecret(), + tokReq.getUsername(),tokReq.getPassword()); + } + + /* (non-Javadoc) + * @see org.onap.aaf.auth.oauth.mapper.Mapper#tokenReq(java.lang.Object) + */ + @Override + public Data clientTokenReq(TokenRequest tokReq, Holder hgt) { + OAuthTokenDAO.Data tdd = new OAuthTokenDAO.Data(); + tdd.client_id = tokReq.getClientId(); + tdd.user = tokReq.getUsername(); + if(tokReq.getRefreshToken()!=null) { + tdd.refresh=tokReq.getRefreshToken(); + } + + for(GRANT_TYPE ttt : GRANT_TYPE.values()) { + if(ttt.name().equals(tokReq.getGrantType())) { + hgt.set(ttt); + break; + } + } + + switch(hgt.get()) { + case client_credentials: + case password: + case refresh_token: + tdd.type = CLIENT_TYPE.confidential.ordinal(); + break; + default: + tdd.type = CLIENT_TYPE.unknown.ordinal(); + break; + } + String scopes=tokReq.getScope(); + if(scopes!=null) { + Set ss = tdd.scopes(true); + for(String s: Split.split(' ', tokReq.getScope())) { + ss.add(s); + } + } + + tdd.state = tokReq.getState(); + return tdd; + } + + @Override + public Result tokenFromData(Result rd) { + if(rd.notOK()) { + return Result.err(rd); + } + Data d = rd.value; + Token token = new Token(); + if(OAuthService.TOKEN_TYPE.values().length>d.type) { + token.setTokenType(OAuthService.TOKEN_TYPE.values()[d.type].name()); + } else { + token.setTokenType("Invalid"); + } + token.setAccessToken(d.id); + token.setRefreshToken(d.refresh); + token.setExpiresIn((int)(d.exp_sec-(System.currentTimeMillis())/1000)); + token.setScope(getScopes(d.scopes(false))); + token.setState(d.state); + return Result.ok(token); + } + + + + /* (non-Javadoc) + * @see org.onap.aaf.auth.oauth.mapper.Mapper#fromPrincipal(org.onap.aaf.cadi.oauth.OAuth2Principal) + */ + @Override + public Introspect fromPrincipal(OAuth2Principal p) { + return p.tokenPerm().getIntrospect(); + } + +} \ No newline at end of file diff --git a/auth/auth-oauth/src/main/java/org/onap/aaf/auth/oauth/mapper/MapperIntrospect.java b/auth/auth-oauth/src/main/java/org/onap/aaf/auth/oauth/mapper/MapperIntrospect.java new file mode 100644 index 00000000..bf558799 --- /dev/null +++ b/auth/auth-oauth/src/main/java/org/onap/aaf/auth/oauth/mapper/MapperIntrospect.java @@ -0,0 +1,29 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.oauth.mapper; + +import org.onap.aaf.auth.dao.cass.OAuthTokenDAO; +import org.onap.aaf.auth.layer.Result; + +public interface MapperIntrospect { + public Result introspect(Result rs); +} diff --git a/auth/auth-oauth/src/main/java/org/onap/aaf/auth/oauth/mapper/MapperIntrospect1_0.java b/auth/auth-oauth/src/main/java/org/onap/aaf/auth/oauth/mapper/MapperIntrospect1_0.java new file mode 100644 index 00000000..00a94fdf --- /dev/null +++ b/auth/auth-oauth/src/main/java/org/onap/aaf/auth/oauth/mapper/MapperIntrospect1_0.java @@ -0,0 +1,74 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.oauth.mapper; + +import java.util.Set; + +import org.onap.aaf.auth.dao.cass.OAuthTokenDAO.Data; +import org.onap.aaf.auth.layer.Result; +import org.onap.aaf.auth.oauth.service.OAuthService.CLIENT_TYPE; + +import aafoauth.v2_0.Introspect; + +public class MapperIntrospect1_0 implements MapperIntrospect { + + public Result introspect(Result rs) { + if(rs.isOKhasData()) { + Data data = rs.value; + Introspect ti = new Introspect(); + ti.setAccessToken(data.id); + ti.setActive(data.active); + ti.setClientId(data.client_id); + for(CLIENT_TYPE ct : CLIENT_TYPE.values()) { + if(data.type==ct.ordinal()) { + ti.setClientType(ct.name()); + break; + } + } + if(ti.getClientType()==null) { + ti.setClientType(CLIENT_TYPE.unknown.name()); + } + ti.setActive(data.active); + ti.setScope(getScopes(data.scopes(false))); + ti.setContent(data.content); + ti.setUsername(data.user); + ti.setExp(data.exp_sec); // want seconds from Jan 1, 1970 + return Result.ok(ti); + } + return Result.err(rs); + } + + protected static String getScopes(Set scopes) { + StringBuilder sb = new StringBuilder(); + boolean start = true; + for(String s : scopes) { + if(start) { + start = false; + } else { + sb.append(' '); + } + sb.append(s); + } + return sb.toString(); + } + +} diff --git a/auth/auth-oauth/src/main/java/org/onap/aaf/auth/oauth/service/JSONPermLoader.java b/auth/auth-oauth/src/main/java/org/onap/aaf/auth/oauth/service/JSONPermLoader.java new file mode 100644 index 00000000..bf04472b --- /dev/null +++ b/auth/auth-oauth/src/main/java/org/onap/aaf/auth/oauth/service/JSONPermLoader.java @@ -0,0 +1,34 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.oauth.service; + +import java.util.Set; + +import org.onap.aaf.auth.env.AuthzTrans; +import org.onap.aaf.auth.layer.Result; +import org.onap.aaf.cadi.CadiException; +import org.onap.aaf.misc.env.APIException; + +public interface JSONPermLoader { + public Result loadJSONPerms(AuthzTrans trans, String user, Set scopes) throws APIException, CadiException; + +} diff --git a/auth/auth-oauth/src/main/java/org/onap/aaf/auth/oauth/service/JSONPermLoaderFactory.java b/auth/auth-oauth/src/main/java/org/onap/aaf/auth/oauth/service/JSONPermLoaderFactory.java new file mode 100644 index 00000000..ea5c595c --- /dev/null +++ b/auth/auth-oauth/src/main/java/org/onap/aaf/auth/oauth/service/JSONPermLoaderFactory.java @@ -0,0 +1,119 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.oauth.service; + +import java.util.List; +import java.util.Set; + +import org.onap.aaf.auth.dao.cass.PermDAO; +import org.onap.aaf.auth.dao.hl.Question; +import org.onap.aaf.auth.env.AuthzTrans; +import org.onap.aaf.auth.layer.Result; +import org.onap.aaf.cadi.CadiException; +import org.onap.aaf.cadi.aaf.v2_0.AAFCon; +import org.onap.aaf.cadi.client.Future; +import org.onap.aaf.cadi.client.Rcli; +import org.onap.aaf.cadi.config.Config; +import org.onap.aaf.misc.env.APIException; +import org.onap.aaf.misc.env.Env; +import org.onap.aaf.misc.env.TimeTaken; + +public class JSONPermLoaderFactory { + /** + * Load JSON Perms from AAF Service (Remotely) + * @param aafcon + * @param timeout + * @return + */ + public static JSONPermLoader remote(final AAFCon aafcon, final int timeout) { + return new JSONPermLoader() { + public Result loadJSONPerms(AuthzTrans trans, String user, Set scopes) throws APIException, CadiException { + Rcli c = aafcon.clientAs(Config.AAF_DEFAULT_VERSION,trans.getUserPrincipal()); + StringBuilder pathinfo = new StringBuilder("/authz/perms/user/"); + pathinfo.append(user); + pathinfo.append("?scopes="); + boolean first = true; + for(String s : scopes) { + if(first) { + first = false; + } else { + pathinfo.append(':'); + } + pathinfo.append(s); + } + TimeTaken tt = trans.start("Call AAF Service", Env.REMOTE); + try { + Future fs = c.read(pathinfo.toString(), "application/Perms+json;charset=utf-8;version=2.0"); + if(fs.get(timeout)) { + return Result.ok(fs.body()); + } else if(fs.code()==404) { + return Result.err(Result.ERR_NotFound,fs.body()); + } else { + return Result.err(Result.ERR_Backend,"Error accessing AAF %s: %s",Integer.toString(fs.code()),fs.body()); + } + } finally { + tt.done(); + } + } + }; + } + public static JSONPermLoader direct(final Question question) { + return new JSONPermLoader() { + public Result loadJSONPerms(AuthzTrans trans, String user, Set scopes) throws APIException, CadiException { + TimeTaken tt = trans.start("Cached DB Perm lookup", Env.SUB); + Result> pd; + try { + pd = question.getPermsByUser(trans, user, false); + } finally { + tt.done(); + } + if(pd.notOK()) { + return Result.err(pd); + } + // Since we know it is + StringBuilder sb = new StringBuilder("{\"perm\":["); + boolean first = true; + for(PermDAO.Data d : pd.value) { + if(scopes.contains(d.ns)) { + if(first) { + first = false; + } else { + sb.append(','); + } + sb.append("{\"type\":\""); + sb.append(d.ns); + sb.append('.'); + sb.append(d.type); + sb.append("\",\"instance\":\""); + sb.append(d.instance); + sb.append("\",\"action\":\""); + sb.append(d.action); + sb.append("\"}"); + } + } + sb.append("]}"); + return Result.ok(sb.toString()); + } + }; + } + +} diff --git a/auth/auth-oauth/src/main/java/org/onap/aaf/auth/oauth/service/OAuthService.java b/auth/auth-oauth/src/main/java/org/onap/aaf/auth/oauth/service/OAuthService.java new file mode 100644 index 00000000..052b292e --- /dev/null +++ b/auth/auth-oauth/src/main/java/org/onap/aaf/auth/oauth/service/OAuthService.java @@ -0,0 +1,301 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.oauth.service; + +import java.io.IOException; +import java.security.GeneralSecurityException; +import java.util.Date; +import java.util.List; +import java.util.Set; +import java.util.UUID; + +import javax.servlet.http.HttpServletRequest; + +import org.onap.aaf.auth.dao.DAO; +import org.onap.aaf.auth.dao.cass.OAuthTokenDAO; +import org.onap.aaf.auth.dao.cass.Status; +import org.onap.aaf.auth.dao.cass.OAuthTokenDAO.Data; +import org.onap.aaf.auth.dao.hl.Question; +import org.onap.aaf.auth.direct.DirectAAFUserPass; +import org.onap.aaf.auth.env.AuthzTrans; +import org.onap.aaf.auth.env.NullTrans; +import org.onap.aaf.auth.layer.Result; +import org.onap.aaf.cadi.Access; +import org.onap.aaf.cadi.CadiException; +import org.onap.aaf.cadi.LocatorException; +import org.onap.aaf.cadi.CredVal.Type; +import org.onap.aaf.cadi.client.Holder; +import org.onap.aaf.cadi.config.Config; +import org.onap.aaf.cadi.oauth.AAFToken; +import org.onap.aaf.cadi.oauth.TokenClient; +import org.onap.aaf.cadi.oauth.TokenClientFactory; +import org.onap.aaf.cadi.util.Split; +import org.onap.aaf.misc.env.APIException; + +import aafoauth.v2_0.Introspect; + +public class OAuthService { + + private static final int TOK_EXP = 60*60*1000; // 1 hour, millis. + + public enum TOKEN_TYPE {unknown,bearer,refresh} + public enum GRANT_TYPE {unknown,password,client_credentials,refresh_token}; + public enum CLIENT_TYPE {unknown,confidential}; + + // Additional Expires + private final DAO[] daos; + public final OAuthTokenDAO tokenDAO; + private final DirectAAFUserPass directUserPass; + private final TokenClientFactory tcf; + private TokenClient altIntrospectClient; + private String altDomain; + private final JSONPermLoader permLoader; + + + // If we add more CAs, may want to parameterize + + @SuppressWarnings("unchecked") + public OAuthService(final Access access, final AuthzTrans trans, final Question q) throws APIException, IOException { + permLoader = JSONPermLoaderFactory.direct(q); + tokenDAO = new OAuthTokenDAO(trans, q.historyDAO); + daos =(DAO[]) new DAO[] { + tokenDAO + }; + try { + String alt_url = access.getProperty(Config.AAF_ALT_OAUTH2_INTROSPECT_URL,null); + if(alt_url!=null) { + tcf = TokenClientFactory.instance(access); + String[] split = Split.split(',', alt_url); + int timeout = split.length>1?Integer.parseInt(split[1]):3000; + altIntrospectClient = tcf.newClient(split[0], timeout); + altIntrospectClient.client_creds(access.getProperty(Config.AAF_ALT_CLIENT_ID,null), + access.getProperty(Config.AAF_ALT_CLIENT_SECRET,null)); + altDomain = '@'+access.getProperty(Config.AAF_ALT_OAUTH2_DOMAIN,null); + } else { + tcf = null; + } + directUserPass = new DirectAAFUserPass(trans.env(), q); + } catch (GeneralSecurityException | CadiException | LocatorException e) { + throw new APIException("Could not construct TokenClientFactory",e); + } + + } + + public Result validate(AuthzTrans trans, OCreds creds) { + if(directUserPass.validate(creds.username, Type.PASSWORD, creds.password, trans)) { + return Result.ok(); + } else { + return Result.err(Result.ERR_Security, "Invalid Credential for ",creds.username); + } + } + + public Result createToken(AuthzTrans trans, HttpServletRequest req, OAuthTokenDAO.Data odd, Holder hgt) { + switch(hgt.get()) { + case client_credentials: + case password: + return createBearerToken(trans, odd); + case refresh_token: + return refreshBearerToken(trans, odd); + default: + return Result.err(Result.ERR_BadData, "Unknown Grant Type"); + } + } + + private Result createBearerToken(AuthzTrans trans, OAuthTokenDAO.Data odd) { + if(odd.user==null) { + odd.user = trans.user(); + } + odd.id = AAFToken.toToken(UUID.randomUUID()); + odd.refresh = AAFToken.toToken(UUID.randomUUID()); + odd.active = true; + long exp; + odd.expires = new Date(exp=(System.currentTimeMillis()+TOK_EXP)); + odd.exp_sec = exp/1000; + odd.req_ip = trans.ip(); + + try { + Result rd = loadToken(trans, odd); + if(rd.notOK()) { + return rd; + } + } catch (APIException | CadiException e) { + return Result.err(e); + } + return tokenDAO.create(trans, odd); + } + + private Result loadToken(AuthzTrans trans, Data odd) throws APIException, CadiException { + Result rs = permLoader.loadJSONPerms(trans,odd.user,odd.scopes(false)); + if(rs.isOK()) { + odd.content = rs.value; + odd.type = TOKEN_TYPE.bearer.ordinal(); + return Result.ok(odd); + } else if(rs.status == Result.ERR_NotFound || rs.status==Status.ERR_UserRoleNotFound) { + odd.type = TOKEN_TYPE.bearer.ordinal(); + return Result.ok(odd); + } else { + return Result.err(Result.ERR_Backend,"Error accessing AAF Info: %s",rs.errorString()); + } + } + + + + private Result refreshBearerToken(AuthzTrans trans, Data odd) { + Result> rld = tokenDAO.readByUser(trans, trans.user()); + if(rld.notOK()) { + return Result.err(rld); + } + if(rld.isEmpty()) { + return Result.err(Result.ERR_NotFound,"Data not Found for %1 %2",trans.user(),odd.refresh==null?"":odd.refresh.toString()); + } + Data token = null; + for(Data d : rld.value) { + if(d.refresh.equals(odd.refresh)) { + token = d; + boolean scopesNE = false; + Set scopes = odd.scopes(false); + if(scopes.size()>0) { // only check if Scopes listed, RFC 6749, Section 6 + if(scopesNE=!(scopes.size() == d.scopes(false).size())) { + for(String s : odd.scopes(false)) { + if(!d.scopes(false).contains(s)) { + scopesNE=true; + break; + } + } + } + if(scopesNE) { + return Result.err(Result.ERR_BadData,"Requested Scopes do not match existing Token"); + } + } + break; + } + } + + if(token==null) { + trans.audit().printf("Duplicate Refresh Token (%s) attempted for %s. Possible Replay Attack",odd.refresh.toString(),trans.user()); + return Result.err(Result.ERR_Security,"Invalid Refresh Token"); + } else { + // Got the Result + Data deleteMe = new Data(); + deleteMe.id = token.id; + token.id = AAFToken.toToken(UUID.randomUUID()); + token.client_id = trans.user(); + token.refresh = AAFToken.toToken(UUID.randomUUID()); + long exp; + token.expires = new Date(exp=(System.currentTimeMillis()+TOK_EXP)); + token.exp_sec = exp/1000; + token.req_ip = trans.ip(); + Result rd = tokenDAO.create(trans, token); + if(rd.notOK()) { + return Result.err(rd); + } + Result rv = tokenDAO.delete(trans, deleteMe,false); + if(rv.notOK()) { + trans.error().log("Unable to delete token", token); + } + } + return Result.ok(token); + } + + public Result introspect(AuthzTrans trans, String token) { + Result> rld; + try { + UUID uuid = AAFToken.fromToken(token); + if(uuid==null) { // not an AAF Token + // Attempt to get Alternative Token + if(altIntrospectClient!=null) { + org.onap.aaf.cadi.client.Result rai = altIntrospectClient.introspect(token); + if(rai.isOK()) { + Introspect in = rai.value; + if(in.getExp()==null) { + trans.audit().printf("Alt OAuth sent back inactive, empty token: requesting_id,%s,access_token=%s,ip=%s\n",trans.user(),token,trans.ip()); + } + long expires = in.getExp()*1000; + if(in.isActive() && expires>System.currentTimeMillis()) { + // We have a good Token, modify to be Fully Qualified + String fqid = in.getUsername()+altDomain; + // read contents + rld = tokenDAO.read(trans, token); + if(rld.isOKhasData()) { + Data td = rld.value.get(0); + in.setContent(td.content); + } else { + Data td = new Data(); + td.id = token; + td.client_id = in.getClientId(); + td.user = fqid; + td.active=true; + td.type = TOKEN_TYPE.bearer.ordinal(); + td.expires = new Date(expires); + td.exp_sec = in.getExp(); + Set scopes = td.scopes(true); + if(in.getScope()!=null) { + for(String s : Split.split(' ', in.getScope())) { + scopes.add(s); + } + } + // td.state = nothing to add at this point + td.req_ip = trans.ip(); + trans.checkpoint(td.user + ':' + td.client_id + ", " + td.id); + return loadToken(trans, td); + } + } +// System.out.println(rai.value.getClientId()); + } else { + trans.audit().printf("Alt OAuth rejects: requesting_id,%s,access_token=%s,ip=%s,code=%d,error=%s\n",trans.user(),token,trans.ip(),rai.code,rai.error); + } + } else { + trans.audit().printf("Bad Token: requesting_id,%s,access_token=%s,ip=%s\n",trans.user(),token,trans.ip()); + } + return Result.err(Result.ERR_Denied,"Bad Token"); + } else { + return dbIntrospect(trans,token); + } + } catch (CadiException | APIException | LocatorException e) { + return Result.err(e); + } + } + + public Result dbIntrospect(final AuthzTrans trans, final String token) { + Result> rld = tokenDAO.read(trans, token); + if(rld.notOKorIsEmpty()) { + return Result.err(rld); + } + OAuthTokenDAO.Data odd = rld.value.get(0); + trans.checkpoint(odd.user + ':' + odd.client_id + ", " + odd.id); + if(odd.active) { + if(odd.expires.before(trans.now())) { + return Result.err(Result.ERR_Policy,"Token %1 has expired",token); + } + return Result.ok(rld.value.get(0)); // ok keyed on id/token. + } else { + return Result.err(Result.ERR_Denied,"Token %1 is inactive",token); + } + } + + public void close() { + for(DAO dao : daos) { + dao.close(NullTrans.singleton()); + } + } + +} diff --git a/auth/auth-oauth/src/main/java/org/onap/aaf/auth/oauth/service/OCreds.java b/auth/auth-oauth/src/main/java/org/onap/aaf/auth/oauth/service/OCreds.java new file mode 100644 index 00000000..becb746a --- /dev/null +++ b/auth/auth-oauth/src/main/java/org/onap/aaf/auth/oauth/service/OCreds.java @@ -0,0 +1,33 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.oauth.service; + +public class OCreds { + public final String client_id, username; + public final byte[] client_secret, password; + public OCreds(String client_id, String client_secret, String username, String password) { + this.client_id = client_id; + this.client_secret = client_secret==null?null:client_secret.getBytes(); + this.username = username; + this.password = password==null?null:password.getBytes(); + } +} diff --git a/auth/auth-service/.gitignore b/auth/auth-service/.gitignore new file mode 100644 index 00000000..940e35eb --- /dev/null +++ b/auth/auth-service/.gitignore @@ -0,0 +1,15 @@ +/.settings +/.classpath +/bin +/common +/logs +/target/ +/tokens/ +/.project +/Dockerfile +/dbuild +/docker-compose.yaml +/drun +/run +/dbuild.orig +/dcy diff --git a/auth/auth-service/pom.xml b/auth/auth-service/pom.xml new file mode 100644 index 00000000..33560e33 --- /dev/null +++ b/auth/auth-service/pom.xml @@ -0,0 +1,144 @@ + + + + 4.0.0 + + org.onap.aaf.auth + parent + 2.1.0-SNAPSHOT + ../pom.xml + + + aaf-auth-service + AAF Auth Service + Core API Component for AAF Auth + + + true + + + + + org.onap.aaf.auth + aaf-auth-client + + + + org.onap.aaf.auth + aaf-auth-core + + + + + org.onap.aaf.auth + aaf-auth-deforg + + + + org.onap.aaf.auth + aaf-auth-cass + + + + org.onap.aaf.auth + aaf-auth-oauth + + + + org.onap.aaf.misc + aaf-misc-rosetta + + + + org.onap.aaf.cadi + aaf-cadi-aaf + + + + org.eclipse.jetty + jetty-servlet + + + + org.slf4j + slf4j-log4j12 + + + + + + + + org.apache.maven.plugins + maven-jar-plugin + + + *.properties + + + 2.3.1 + + + org.apache.maven.plugins + maven-deploy-plugin + + true + + + + org.codehaus.mojo + appassembler-maven-plugin + + + + org.onap.aaf.auth.service.AAF_Service + service + + cadi_prop_files=${project.conf_dir}/org.osaaf.service.props + + + + + + + + + + + + nexus + attarch-releases + http://mavencentral.it.att.com:8084/nexus/content/repositories/attarch-releases + + + nexus + attarch-snapshots + http://mavencentral.it.att.com:8084/nexus/content/repositories/attarch-snapshots + + + diff --git a/auth/auth-service/src/main/config/.gitignore b/auth/auth-service/src/main/config/.gitignore new file mode 100644 index 00000000..508486a3 --- /dev/null +++ b/auth/auth-service/src/main/config/.gitignore @@ -0,0 +1,2 @@ +/authAPI.props +/log4j.properties diff --git a/auth/auth-service/src/main/docker/.gitignore b/auth/auth-service/src/main/docker/.gitignore new file mode 100644 index 00000000..508486a3 --- /dev/null +++ b/auth/auth-service/src/main/docker/.gitignore @@ -0,0 +1,2 @@ +/authAPI.props +/log4j.properties diff --git a/auth/auth-service/src/main/java/org/onap/aaf/auth/service/AAF_Service.java b/auth/auth-service/src/main/java/org/onap/aaf/auth/service/AAF_Service.java new file mode 100644 index 00000000..ad9ccc4a --- /dev/null +++ b/auth/auth-service/src/main/java/org/onap/aaf/auth/service/AAF_Service.java @@ -0,0 +1,227 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.service; + +import javax.servlet.Filter; + +import org.onap.aaf.auth.cache.Cache; +import org.onap.aaf.auth.dao.CassAccess; +import org.onap.aaf.auth.dao.hl.Question; +import org.onap.aaf.auth.direct.DirectAAFLur; +import org.onap.aaf.auth.direct.DirectAAFUserPass; +import org.onap.aaf.auth.direct.DirectCertIdentity; +import org.onap.aaf.auth.direct.DirectLocatorCreator; +import org.onap.aaf.auth.direct.DirectRegistrar; +import org.onap.aaf.auth.env.AuthzEnv; +import org.onap.aaf.auth.env.AuthzTrans; +import org.onap.aaf.auth.env.AuthzTransFilter; +import org.onap.aaf.auth.org.OrganizationFactory; +import org.onap.aaf.auth.rserv.HttpMethods; +import org.onap.aaf.auth.server.AbsService; +import org.onap.aaf.auth.server.JettyServiceStarter; +import org.onap.aaf.auth.service.api.API_Api; +import org.onap.aaf.auth.service.api.API_Approval; +import org.onap.aaf.auth.service.api.API_Creds; +import org.onap.aaf.auth.service.api.API_Delegate; +import org.onap.aaf.auth.service.api.API_History; +import org.onap.aaf.auth.service.api.API_Mgmt; +import org.onap.aaf.auth.service.api.API_NS; +import org.onap.aaf.auth.service.api.API_Perms; +import org.onap.aaf.auth.service.api.API_Roles; +import org.onap.aaf.auth.service.api.API_User; +import org.onap.aaf.auth.service.api.API_UserRole; +import org.onap.aaf.auth.service.facade.AuthzFacadeFactory; +import org.onap.aaf.auth.service.facade.AuthzFacade_2_0; +import org.onap.aaf.auth.service.mapper.Mapper.API; +import org.onap.aaf.cadi.CadiException; +import org.onap.aaf.cadi.PropAccess; +import org.onap.aaf.cadi.aaf.v2_0.AAFTrustChecker; +import org.onap.aaf.cadi.aaf.v2_0.AbsAAFLocator; +import org.onap.aaf.cadi.config.Config; +import org.onap.aaf.cadi.register.Registrant; +import org.onap.aaf.cadi.taf.basic.BasicHttpTaf; +import org.onap.aaf.misc.env.APIException; +import org.onap.aaf.misc.env.Data; +import org.onap.aaf.misc.env.Env; + +import com.datastax.driver.core.Cluster; + +public class AAF_Service extends AbsService { + + private static final String ORGANIZATION = "Organization."; + private static final String DOMAIN = "aaf.att.com"; + +// TODO Add Service Metrics +// private Metric serviceMetric; + public final Question question; +// private final SessionFilter sessionFilter; + private AuthzFacade_2_0 facade; + private AuthzFacade_2_0 facade_XML; + private DirectAAFUserPass directAAFUserPass; + private final Cluster cluster; + //private final OAuthService oauthService; + + /** + * Construct AuthzAPI with all the Context Supporting Routes that Authz needs + * + * @param env + * @param decryptor + * @throws APIException + */ + public AAF_Service( final AuthzEnv env) throws Exception { + super(env.access(), env); + + // Initialize Facade for all uses + AuthzTrans trans = env.newTrans(); + + cluster = org.onap.aaf.auth.dao.CassAccess.cluster(env,null); + + // Need Question for Security purposes (direct User/Authz Query in Filter) + // Start Background Processing + question = new Question(trans, cluster, CassAccess.KEYSPACE, true); + DirectCertIdentity.set(question.certDAO); + + // Have AAFLocator object Create DirectLocators for Location needs + AbsAAFLocator.setCreator(new DirectLocatorCreator(env, question.locateDAO)); + + // Initialize Organizations... otherwise, first pass may miss + int org_size = ORGANIZATION.length(); + for(String n : env.existingStaticSlotNames()) { + if(n.startsWith(ORGANIZATION)) { + OrganizationFactory.obtain(env, n.substring(org_size)); + } + } + + + // For direct Introspection needs. + //oauthService = new OAuthService(trans, question); + + facade = AuthzFacadeFactory.v2_0(env,trans,Data.TYPE.JSON,question); + facade_XML = AuthzFacadeFactory.v2_0(env,trans,Data.TYPE.XML,question); + + directAAFUserPass = new DirectAAFUserPass(trans.env(),question); + + // Print results and cleanup + StringBuilder sb = new StringBuilder(); + trans.auditTrail(0, sb); + if(sb.length()>0)env.init().log(sb); + trans = null; + sb = null; + + //////////////////////////////////////////////////////////////////////////// + // Time Critical + // These will always be evaluated first + //////////////////////////////////////////////////////////////////////// + API_Creds.timeSensitiveInit(env, this, facade,directAAFUserPass); + API_Perms.timeSensitiveInit(this, facade); + //////////////////////////////////////////////////////////////////////// + // Service APIs + //////////////////////////////////////////////////////////////////////// + API_Creds.init(this, facade); + API_UserRole.init(this, facade); + API_Roles.init(this, facade); + API_Perms.init(this, facade); + API_NS.init(this, facade); + API_User.init(this, facade); + API_Delegate.init(this,facade); + API_Approval.init(this, facade); + API_History.init(this, facade); + + //////////////////////////////////////////////////////////////////////// + // Management APIs + //////////////////////////////////////////////////////////////////////// + // There are several APIs around each concept, and it gets a bit too + // long in this class to create. The initialization of these Management + // APIs have therefore been pushed to StandAlone Classes with static + // init functions + API_Mgmt.init(this, facade); + API_Api.init(this, facade); + + } + + @Override + public Filter[] filters() throws CadiException { + try { + return new Filter[] {new AuthzTransFilter(env, null /* no connection to AAF... it is AAF */, + new AAFTrustChecker((Env)env), + new DirectAAFLur(env,question), // Note, this will be assigned by AuthzTransFilter to TrustChecker + //new DirectOAuthTAF(env,question,OAFacadeFactory.directV1_0(oauthService)), + new BasicHttpTaf(env, directAAFUserPass, + DOMAIN,Long.parseLong(env.getProperty(Config.AAF_CLEAN_INTERVAL, Config.AAF_CLEAN_INTERVAL_DEF)), + false) + )}; + } catch (NumberFormatException e) { + throw new CadiException("Invalid Property information", e); + } + } + + @SuppressWarnings("unchecked") + @Override + public Registrant[] registrants(final int port) throws CadiException { + return new Registrant[] { + new DirectRegistrar(access,question.locateDAO,app_name,app_interface_version,port) + }; + } + + @Override + public void destroy() { + Cache.stopTimer(); + if(cluster!=null) { + cluster.close(); + } + super.destroy(); + } + + + /** + * Setup XML and JSON implementations for each supported Version type + * + * We do this by taking the Code passed in and creating clones of these with the appropriate Facades and properties + * to do Versions and Content switches + * + */ + public void route(HttpMethods meth, String path, API api, Code code) throws Exception { + String version = "2.0"; + Class respCls = facade.mapper().getClass(api); + if(respCls==null) throw new Exception("Unknown class associated with " + api.getClass().getName() + ' ' + api.name()); + String application = applicationJSON(respCls, version); + + route(env,meth,path,code,application,"application/json;version=2.0","*/*"); + application = applicationXML(respCls, version); + route(env,meth,path,code.clone(facade_XML,false),application,"text/xml;version=2.0"); + } + + /** + * Start up AAF_Service as Jetty Service + */ + public static void main(final String[] args) { + PropAccess propAccess = new PropAccess(args); + try { + AAF_Service service = new AAF_Service(new AuthzEnv(propAccess)); +// service.env().setLog4JNames("log4j.properties","authz","authz|service","audit","init","trace"); + JettyServiceStarter jss = new JettyServiceStarter(service); + jss.start(); + } catch (Exception e) { + e.printStackTrace(); + } + } +} diff --git a/auth/auth-service/src/main/java/org/onap/aaf/auth/service/AuthzCassServiceImpl.java b/auth/auth-service/src/main/java/org/onap/aaf/auth/service/AuthzCassServiceImpl.java new file mode 100644 index 00000000..fa099111 --- /dev/null +++ b/auth/auth-service/src/main/java/org/onap/aaf/auth/service/AuthzCassServiceImpl.java @@ -0,0 +1,4245 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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==================================================== + * + */ + +package org.onap.aaf.auth.service; + +import static org.onap.aaf.auth.env.AuthzTrans.REQD_TYPE.force; +import static org.onap.aaf.auth.env.AuthzTrans.REQD_TYPE.future; +import static org.onap.aaf.auth.layer.Result.OK; +import static org.onap.aaf.auth.rserv.HttpMethods.DELETE; +import static org.onap.aaf.auth.rserv.HttpMethods.GET; +import static org.onap.aaf.auth.rserv.HttpMethods.POST; +import static org.onap.aaf.auth.rserv.HttpMethods.PUT; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Comparator; +import java.util.Date; +import java.util.GregorianCalendar; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.TreeMap; +import java.util.UUID; + +import javax.servlet.http.HttpServletRequest; + +import org.onap.aaf.auth.common.Define; +import org.onap.aaf.auth.dao.DAOException; +import org.onap.aaf.auth.dao.cass.ApprovalDAO; +import org.onap.aaf.auth.dao.cass.CertDAO; +import org.onap.aaf.auth.dao.cass.CredDAO; +import org.onap.aaf.auth.dao.cass.DelegateDAO; +import org.onap.aaf.auth.dao.cass.FutureDAO; +import org.onap.aaf.auth.dao.cass.HistoryDAO; +import org.onap.aaf.auth.dao.cass.Namespace; +import org.onap.aaf.auth.dao.cass.NsDAO; +import org.onap.aaf.auth.dao.cass.NsDAO.Data; +import org.onap.aaf.auth.dao.cass.NsSplit; +import org.onap.aaf.auth.dao.cass.NsType; +import org.onap.aaf.auth.dao.cass.PermDAO; +import org.onap.aaf.auth.dao.cass.RoleDAO; +import org.onap.aaf.auth.dao.cass.Status; +import org.onap.aaf.auth.dao.cass.UserRoleDAO; +import org.onap.aaf.auth.dao.hl.CassExecutor; +import org.onap.aaf.auth.dao.hl.Function; +import org.onap.aaf.auth.dao.hl.Function.FUTURE_OP; +import org.onap.aaf.auth.dao.hl.Function.Lookup; +import org.onap.aaf.auth.dao.hl.Function.OP_STATUS; +import org.onap.aaf.auth.dao.hl.Question; +import org.onap.aaf.auth.dao.hl.Question.Access; +import org.onap.aaf.auth.env.AuthzTrans; +import org.onap.aaf.auth.layer.Result; +import org.onap.aaf.auth.org.Executor; +import org.onap.aaf.auth.org.Organization; +import org.onap.aaf.auth.org.Organization.Expiration; +import org.onap.aaf.auth.org.Organization.Identity; +import org.onap.aaf.auth.org.Organization.Policy; +import org.onap.aaf.auth.org.OrganizationException; +import org.onap.aaf.auth.rserv.doc.ApiDoc; +import org.onap.aaf.auth.service.mapper.Mapper; +import org.onap.aaf.auth.service.mapper.Mapper.API; +import org.onap.aaf.auth.service.validation.ServiceValidator; +import org.onap.aaf.auth.validation.Validator; +import org.onap.aaf.cadi.principal.BasicPrincipal; +import org.onap.aaf.misc.env.Env; +import org.onap.aaf.misc.env.TimeTaken; +import org.onap.aaf.misc.env.util.Chrono; +import org.onap.aaf.misc.env.util.Split; + +import aaf.v2_0.CredRequest; + +/** + * AuthzCassServiceImpl implements AuthzCassService for + * + * @author Jonathan + * + * @param + * @param + * @param + * @param + * @param + * @param + * @param + * @param + * @param + * @param + */ +public class AuthzCassServiceImpl + implements AuthzService { + + private Mapper mapper; + @Override + public Mapper mapper() {return mapper;} + + private static final String ASTERIX = "*"; + private static final String CACHE = "cache"; + private static final String ROOT_NS = Define.ROOT_NS(); + private static final String ROOT_COMPANY = Define.ROOT_COMPANY(); + + private final Question ques; + private final Function func; + + public AuthzCassServiceImpl(AuthzTrans trans, Mapper mapper,Question question) { + this.ques = question; + func = new Function(trans, question); + this.mapper = mapper; + + } + +/*********************************** + * NAMESPACE + ***********************************/ + /** + * createNS + * @throws DAOException + * @see org.onap.aaf.auth.service.AuthzService#createNS(org.onap.aaf.auth.env.test.AuthzTrans, java.lang.String, java.lang.String) + */ + @ApiDoc( + method = POST, + path = "/authz/ns", + params = {}, + expectedCode = 201, + errorCodes = { 403,404,406,409 }, + text = { "Namespace consists of: ", + "

    ", + "Note: Namespaces are dot-delimited (i.e. com.myCompany.myApp) and must be ", + "created with parent credentials (i.e. To create com.myCompany.myApp, you must ", + "be an admin of com.myCompany or com" + } + ) + @Override + public Result createNS(final AuthzTrans trans, REQUEST from, NsType type) { + final Result rnamespace = mapper.ns(trans, from); + final ServiceValidator v = new ServiceValidator(); + if(v.ns(rnamespace).err()) { + return Result.err(Status.ERR_BadData,v.errs()); + } + final Namespace namespace = rnamespace.value; + final Result parentNs = ques.deriveNs(trans,namespace.name); + if(parentNs.notOK()) { + return Result.err(parentNs); + } + + if(namespace.name.lastIndexOf('.')<0) { // Root Namespace... Function will check if allowed + return func.createNS(trans, namespace, false); + } + + Result fd = mapper.future(trans, NsDAO.TABLE,from,namespace,true, + new Mapper.Memo() { + @Override + public String get() { + return "Create Namespace [" + namespace.name + ']'; + } + }, + new MayChange() { + private Result rnd; + @Override + public Result mayChange() { + if(rnd==null) { + rnd = ques.mayUser(trans, trans.user(), parentNs.value,Access.write); + } + return rnd; + } + }); + switch(fd.status) { + case OK: + Result rfc = func.createFuture(trans, fd.value, namespace.name, trans.user(),parentNs.value, FUTURE_OP.C); + if(rfc.isOK()) { + return Result.err(Status.ACC_Future, "NS [%s] is saved for future processing",namespace.name); + } else { + return Result.err(rfc); + } + case Status.ACC_Now: + return func.createNS(trans, namespace, false); + default: + return Result.err(fd); + } + } + + @ApiDoc( + method = POST, + path = "/authz/ns/:ns/admin/:id", + params = { "ns|string|true", + "id|string|true" + }, + expectedCode = 201, + errorCodes = { 403,404,406,409 }, + text = { "Add an Identity :id to the list of Admins for the Namespace :ns", + "Note: :id must be fully qualified (i.e. ab1234@csp.att.com)" } + ) + @Override + public Result addAdminNS(AuthzTrans trans, String ns, String id) { + return func.addUserRole(trans, id, ns,Question.ADMIN); + } + + @ApiDoc( + method = DELETE, + path = "/authz/ns/:ns/admin/:id", + params = { "ns|string|true", + "id|string|true" + }, + expectedCode = 200, + errorCodes = { 403,404 }, + text = { "Remove an Identity :id from the list of Admins for the Namespace :ns", + "Note: :id must be fully qualified (i.e. ab1234@csp.att.com)" } + ) + @Override + public Result delAdminNS(AuthzTrans trans, String ns, String id) { + return func.delAdmin(trans,ns,id); + } + + @ApiDoc( + method = POST, + path = "/authz/ns/:ns/responsible/:id", + params = { "ns|string|true", + "id|string|true" + }, + expectedCode = 201, + errorCodes = { 403,404,406,409 }, + text = { "Add an Identity :id to the list of Responsibles for the Namespace :ns", + "Note: :id must be fully qualified (i.e. ab1234@csp.att.com)" } + ) + @Override + public Result addResponsibleNS(AuthzTrans trans, String ns, String id) { + return func.addUserRole(trans,id,ns,Question.OWNER); + } + + @ApiDoc( + method = DELETE, + path = "/authz/ns/:ns/responsible/:id", + params = { "ns|string|true", + "id|string|true" + }, + expectedCode = 200, + errorCodes = { 403,404 }, + text = { "Remove an Identity :id to the list of Responsibles for the Namespace :ns", + "Note: :id must be fully qualified (i.e. ab1234@csp.att.com)", + "Note: A namespace must have at least 1 responsible party" + } + ) + @Override + public Result delResponsibleNS(AuthzTrans trans, String ns, String id) { + return func.delOwner(trans,ns,id); + } + + /* (non-Javadoc) + * @see org.onap.aaf.auth.service.AuthzService#applyModel(org.onap.aaf.auth.env.test.AuthzTrans, java.lang.Object) + */ + @ApiDoc( + method = POST, + path = "/authz/ns/:ns/attrib/:key/:value", + params = { "ns|string|true", + "key|string|true", + "value|string|true"}, + expectedCode = 201, + errorCodes = { 403,404,406,409 }, + text = { + "Create an attribute in the Namespace", + "You must be given direct permission for key by AAF" + } + ) + @Override + public Result createNsAttrib(AuthzTrans trans, String ns, String key, String value) { + TimeTaken tt = trans.start("Create NsAttrib " + ns + ':' + key + ':' + value, Env.SUB); + try { + // Check inputs + final Validator v = new ServiceValidator(); + if(v.ns(ns).err() || + v.key(key).err() || + v.value(value).err()) { + return Result.err(Status.ERR_BadData,v.errs()); + } + + // Check if exists already + Result> rlnsd = ques.nsDAO.read(trans, ns); + if(rlnsd.notOKorIsEmpty()) { + return Result.err(rlnsd); + } + NsDAO.Data nsd = rlnsd.value.get(0); + + // Check for Existence + if(nsd.attrib.get(key)!=null) { + return Result.err(Status.ERR_ConflictAlreadyExists, "NS Property %s:%s exists", ns, key); + } + + // Check if User may put + if(!ques.isGranted(trans, trans.user(), ROOT_NS, Question.ATTRIB, + ":"+trans.org().getDomain()+".*:"+key, Access.write.name())) { + return Result.err(Status.ERR_Denied, "%s may not create NS Attrib [%s:%s]", trans.user(),ns, key); + } + + // Add Attrib + nsd.attrib.put(key, value); + ques.nsDAO.dao().attribAdd(trans,ns,key,value); + return Result.ok(); + } finally { + tt.done(); + } + } + + @ApiDoc( + method = GET, + path = "/authz/ns/attrib/:key", + params = { "key|string|true" }, + expectedCode = 200, + errorCodes = { 403,404 }, + text = { + "Read Attributes for Namespace" + } + ) + @Override + public Result readNsByAttrib(AuthzTrans trans, String key) { + // Check inputs + final Validator v = new ServiceValidator(); + if(v.nullOrBlank("Key",key).err()) { + return Result.err(Status.ERR_BadData,v.errs()); + } + + // May Read + if(!ques.isGranted(trans, trans.user(), ROOT_NS, Question.ATTRIB, + ":"+trans.org().getDomain()+".*:"+key, Question.READ)) { + return Result.err(Status.ERR_Denied,"%s may not read NS by Attrib '%s'",trans.user(),key); + } + + Result> rsd = ques.nsDAO.dao().readNsByAttrib(trans, key); + if(rsd.notOK()) { + return Result.err(rsd); + } + return mapper().keys(rsd.value); + } + + + @ApiDoc( + method = PUT, + path = "/authz/ns/:ns/attrib/:key/:value", + params = { "ns|string|true", + "key|string|true"}, + expectedCode = 200, + errorCodes = { 403,404 }, + text = { + "Update Value on an existing attribute in the Namespace", + "You must be given direct permission for key by AAF" + } + ) + @Override + public Result updateNsAttrib(AuthzTrans trans, String ns, String key, String value) { + TimeTaken tt = trans.start("Update NsAttrib " + ns + ':' + key + ':' + value, Env.SUB); + try { + // Check inputs + final Validator v = new ServiceValidator(); + if(v.ns(ns).err() || + v.key(key).err() || + v.value(value).err()) { + return Result.err(Status.ERR_BadData,v.errs()); + } + + // Check if exists already (NS must exist) + Result> rlnsd = ques.nsDAO.read(trans, ns); + if(rlnsd.notOKorIsEmpty()) { + return Result.err(rlnsd); + } + NsDAO.Data nsd = rlnsd.value.get(0); + + // Check for Existence + if(nsd.attrib.get(key)==null) { + return Result.err(Status.ERR_NotFound, "NS Property %s:%s exists", ns, key); + } + + // Check if User may put + if(!ques.isGranted(trans, trans.user(), ROOT_NS, Question.ATTRIB, + ":"+trans.org().getDomain()+".*:"+key, Access.write.name())) { + return Result.err(Status.ERR_Denied, "%s may not create NS Attrib [%s:%s]", trans.user(),ns, key); + } + + // Add Attrib + nsd.attrib.put(key, value); + + return ques.nsDAO.update(trans,nsd); + + } finally { + tt.done(); + } + } + + @ApiDoc( + method = DELETE, + path = "/authz/ns/:ns/attrib/:key", + params = { "ns|string|true", + "key|string|true"}, + expectedCode = 200, + errorCodes = { 403,404 }, + text = { + "Delete an attribute in the Namespace", + "You must be given direct permission for key by AAF" + } + ) + @Override + public Result deleteNsAttrib(AuthzTrans trans, String ns, String key) { + TimeTaken tt = trans.start("Delete NsAttrib " + ns + ':' + key, Env.SUB); + try { + // Check inputs + final Validator v = new ServiceValidator(); + if(v.nullOrBlank("NS",ns).err() || + v.nullOrBlank("Key",key).err()) { + return Result.err(Status.ERR_BadData,v.errs()); + } + + // Check if exists already + Result> rlnsd = ques.nsDAO.read(trans, ns); + if(rlnsd.notOKorIsEmpty()) { + return Result.err(rlnsd); + } + NsDAO.Data nsd = rlnsd.value.get(0); + + // Check for Existence + if(nsd.attrib.get(key)==null) { + return Result.err(Status.ERR_NotFound, "NS Property [%s:%s] does not exist", ns, key); + } + + // Check if User may del + if(!ques.isGranted(trans, trans.user(), ROOT_NS, "attrib", ":" + ROOT_COMPANY + ".*:"+key, Access.write.name())) { + return Result.err(Status.ERR_Denied, "%s may not delete NS Attrib [%s:%s]", trans.user(),ns, key); + } + + // Add Attrib + nsd.attrib.remove(key); + ques.nsDAO.dao().attribRemove(trans,ns,key); + return Result.ok(); + } finally { + tt.done(); + } + } + + @ApiDoc( + method = GET, + path = "/authz/nss/:id", + params = { "id|string|true" }, + expectedCode = 200, + errorCodes = { 404,406 }, + text = { + "Lists the Admin(s), Responsible Party(s), Role(s), Permission(s)", + "Credential(s) and Expiration of Credential(s) in Namespace :id", + } + ) + @Override + public Result getNSbyName(AuthzTrans trans, String ns) { + final Validator v = new ServiceValidator(); + if(v.nullOrBlank("NS", ns).err()) { + return Result.err(Status.ERR_BadData,v.errs()); + } + + Result> rlnd = ques.nsDAO.read(trans, ns); + if(rlnd.isOK()) { + if(rlnd.isEmpty()) { + return Result.err(Status.ERR_NotFound, "No data found for %s",ns); + } + Result rnd = ques.mayUser(trans, trans.user(), rlnd.value.get(0), Access.read); + if(rnd.notOK()) { + return Result.err(rnd); + } + + + Namespace namespace = new Namespace(rnd.value); + Result> rd = func.getOwners(trans, namespace.name, false); + if(rd.isOK()) { + namespace.owner = rd.value; + } + rd = func.getAdmins(trans, namespace.name, false); + if(rd.isOK()) { + namespace.admin = rd.value; + } + + NSS nss = mapper.newInstance(API.NSS); + return mapper.nss(trans, namespace, nss); + } else { + return Result.err(rlnd); + } + } + + @ApiDoc( + method = GET, + path = "/authz/nss/admin/:id", + params = { "id|string|true" }, + expectedCode = 200, + errorCodes = { 403,404 }, + text = { "Lists all Namespaces where Identity :id is an Admin", + "Note: :id must be fully qualified (i.e. ab1234@csp.att.com)" + } + ) + @Override + public Result getNSbyAdmin(AuthzTrans trans, String user, boolean full) { + final Validator v = new ServiceValidator(); + if (v.nullOrBlank("User", user).err()) { + return Result.err(Status.ERR_BadData, v.errs()); + } + + Result> rn = loadNamepace(trans, user, ".admin", full); + if(rn.notOK()) { + return Result.err(rn); + } + if (rn.isEmpty()) { + return Result.err(Status.ERR_NotFound, "[%s] is not an admin for any namespaces",user); + } + NSS nss = mapper.newInstance(API.NSS); + // Note: "loadNamespace" already validates view of Namespace + return mapper.nss(trans, rn.value, nss); + + } + + @ApiDoc( + method = GET, + path = "/authz/nss/either/:id", + params = { "id|string|true" }, + expectedCode = 200, + errorCodes = { 403,404 }, + text = { "Lists all Namespaces where Identity :id is either an Admin or an Owner", + "Note: :id must be fully qualified (i.e. ab1234@csp.att.com)" + } + ) + @Override + public Result getNSbyEither(AuthzTrans trans, String user, boolean full) { + final Validator v = new ServiceValidator(); + if (v.nullOrBlank("User", user).err()) { + return Result.err(Status.ERR_BadData, v.errs()); + } + + Result> rn = loadNamepace(trans, user, null, full); + if(rn.notOK()) { + return Result.err(rn); + } + if (rn.isEmpty()) { + return Result.err(Status.ERR_NotFound, "[%s] is not an admin or owner for any namespaces",user); + } + NSS nss = mapper.newInstance(API.NSS); + // Note: "loadNamespace" already validates view of Namespace + return mapper.nss(trans, rn.value, nss); + } + + private Result> loadNamepace(AuthzTrans trans, String user, String endsWith, boolean full) { + Result> urd = ques.userRoleDAO.readByUser(trans, user); + if(urd.notOKorIsEmpty()) { + return Result.err(urd); + } + Map lm = new HashMap(); + Map other = full || endsWith==null?null:new TreeMap(); + for(UserRoleDAO.Data urdd : urd.value) { + if(full) { + if(endsWith==null || urdd.role.endsWith(endsWith)) { + RoleDAO.Data rd = RoleDAO.Data.decode(urdd); + Result nsd = ques.mayUser(trans, user, rd, Access.read); + if(nsd.isOK()) { + Namespace namespace = lm.get(nsd.value.name); + if(namespace==null) { + namespace = new Namespace(nsd.value); + lm.put(namespace.name,namespace); + } + Result> rls = func.getAdmins(trans, namespace.name, false); + if(rls.isOK()) { + namespace.admin=rls.value; + } + + rls = func.getOwners(trans, namespace.name, false); + if(rls.isOK()) { + namespace.owner=rls.value; + } + } + } + } else { // Shortened version. Only Namespace Info available from Role. + if(Question.ADMIN.equals(urdd.rname) || Question.OWNER.equals(urdd.rname)) { + RoleDAO.Data rd = RoleDAO.Data.decode(urdd); + Result nsd = ques.mayUser(trans, user, rd, Access.read); + if(nsd.isOK()) { + Namespace namespace = lm.get(nsd.value.name); + if(namespace==null) { + if(other!=null) { + namespace = other.remove(nsd.value.name); + } + if(namespace==null) { + namespace = new Namespace(nsd.value); + namespace.admin=new ArrayList(); + namespace.owner=new ArrayList(); + } + if(endsWith==null || urdd.role.endsWith(endsWith)) { + lm.put(namespace.name,namespace); + } else { + other.put(namespace.name,namespace); + } + } + if(Question.OWNER.equals(urdd.rname)) { + namespace.owner.add(urdd.user); + } else { + namespace.admin.add(urdd.user); + } + } + } + } + } + return Result.ok(lm.values()); + } + + @ApiDoc( + method = GET, + path = "/authz/nss/responsible/:id", + params = { "id|string|true" }, + expectedCode = 200, + errorCodes = { 403,404 }, + text = { "Lists all Namespaces where Identity :id is a Responsible Party", + "Note: :id must be fully qualified (i.e. ab1234@csp.att.com)" + } + ) + @Override + public Result getNSbyResponsible(AuthzTrans trans, String user, boolean full) { + final Validator v = new ServiceValidator(); + if (v.nullOrBlank("User", user).err()) { + return Result.err(Status.ERR_BadData, v.errs()); + } + Result> rn = loadNamepace(trans, user, ".owner",full); + if(rn.notOK()) { + return Result.err(rn); + } + if (rn.isEmpty()) { + return Result.err(Status.ERR_NotFound, "[%s] is not an owner for any namespaces",user); + } + NSS nss = mapper.newInstance(API.NSS); + // Note: "loadNamespace" prevalidates + return mapper.nss(trans, rn.value, nss); + } + + @ApiDoc( + method = GET, + path = "/authz/nss/children/:id", + params = { "id|string|true" }, + expectedCode = 200, + errorCodes = { 403,404 }, + text = { "Lists all Child Namespaces of Namespace :id", + "Note: This is not a cached read" + } + ) + @Override + public Result getNSsChildren(AuthzTrans trans, String parent) { + final Validator v = new ServiceValidator(); + if(v.nullOrBlank("NS", parent).err()) { + return Result.err(Status.ERR_BadData,v.errs()); + } + + Result rnd = ques.deriveNs(trans, parent); + if(rnd.notOK()) { + return Result.err(rnd); + } + rnd = ques.mayUser(trans, trans.user(), rnd.value, Access.read); + if(rnd.notOK()) { + return Result.err(rnd); + } + + Set lm = new HashSet(); + Result> rlnd = ques.nsDAO.dao().getChildren(trans, parent); + if(rlnd.isOK()) { + if(rlnd.isEmpty()) { + return Result.err(Status.ERR_NotFound, "No data found for %s",parent); + } + for(NsDAO.Data ndd : rlnd.value) { + Namespace namespace = new Namespace(ndd); + Result> rls = func.getAdmins(trans, namespace.name, false); + if(rls.isOK()) { + namespace.admin=rls.value; + } + + rls = func.getOwners(trans, namespace.name, false); + if(rls.isOK()) { + namespace.owner=rls.value; + } + + lm.add(namespace); + } + NSS nss = mapper.newInstance(API.NSS); + return mapper.nss(trans,lm, nss); + } else { + return Result.err(rlnd); + } + } + + + @ApiDoc( + method = PUT, + path = "/authz/ns", + params = {}, + expectedCode = 200, + errorCodes = { 403,404,406 }, + text = { "Replace the Current Description of a Namespace with a new one" + } + ) + @Override + public Result updateNsDescription(AuthzTrans trans, REQUEST from) { + final Result nsd = mapper.ns(trans, from); + final ServiceValidator v = new ServiceValidator(); + if(v.ns(nsd).err()) { + return Result.err(Status.ERR_BadData,v.errs()); + } + if(v.nullOrBlank("description", nsd.value.description).err()) { + return Result.err(Status.ERR_BadData,v.errs()); + } + + Namespace namespace = nsd.value; + Result> rlnd = ques.nsDAO.read(trans, namespace.name); + + if(rlnd.notOKorIsEmpty()) { + return Result.err(Status.ERR_NotFound, "Namespace [%s] does not exist",namespace.name); + } + + if (ques.mayUser(trans, trans.user(), rlnd.value.get(0), Access.write).notOK()) { + return Result.err(Status.ERR_Denied, "You do not have approval to change %s",namespace.name); + } + + Result rdr = ques.nsDAO.dao().addDescription(trans, namespace.name, namespace.description); + if(rdr.isOK()) { + return Result.ok(); + } else { + return Result.err(rdr); + } + } + + /** + * deleteNS + * @throws DAOException + * @see org.onap.aaf.auth.service.AuthzService#deleteNS(org.onap.aaf.auth.env.test.AuthzTrans, java.lang.String, java.lang.String) + */ + @ApiDoc( + method = DELETE, + path = "/authz/ns/:ns", + params = { "ns|string|true" }, + expectedCode = 200, + errorCodes = { 403,404,424 }, + text = { "Delete the Namespace :ns. Namespaces cannot normally be deleted when there ", + "are still credentials associated with them, but they can be deleted by setting ", + "the \"force\" property. To do this: Add 'force=true' as a query parameter", + "

    WARNING: Using force will delete all credentials attached to this namespace. Use with care.

    " + + "if the \"force\" property is set to 'force=move', then Permissions and Roles are not deleted," + + "but are retained, and assigned to the Parent Namespace. 'force=move' is not permitted " + + "at or below Application Scope" + } + ) + @Override + public Result deleteNS(AuthzTrans trans, String ns) { + return func.deleteNS(trans, ns); + } + + +/*********************************** + * PERM + ***********************************/ + + /* + * (non-Javadoc) + * @see org.onap.aaf.auth.service.AuthzService#createOrUpdatePerm(org.onap.aaf.auth.env.test.AuthzTrans, java.lang.Object, boolean, java.lang.String, java.lang.String, java.lang.String, java.util.List, java.util.List) + */ + @ApiDoc( + method = POST, + path = "/authz/perm", + params = {}, + expectedCode = 201, + errorCodes = {403,404,406,409}, + text = { "Permission consists of:", + "
    • type - a Namespace qualified identifier specifying what kind of resource " + + "is being protected
    • ", + "
    • instance - a key, possibly multi-dimensional, that identifies a specific " + + " instance of the type
    • ", + "
    • action - what kind of action is allowed
    ", + "Note: instance and action can be an *" + } + ) + @Override + public Result createPerm(final AuthzTrans trans,REQUEST rreq) { + final Result newPd = mapper.perm(trans, rreq); + final ServiceValidator v = new ServiceValidator(); + if(v.perm(newPd).err()) { + return Result.err(Status.ERR_BadData,v.errs()); + } + + Result fd = mapper.future(trans, PermDAO.TABLE, rreq, newPd.value,false, + new Mapper.Memo() { + @Override + public String get() { + return "Create Permission [" + + newPd.value.fullType() + '|' + + newPd.value.instance + '|' + + newPd.value.action + ']'; + } + }, + new MayChange() { + private Result nsd; + @Override + public Result mayChange() { + if(nsd==null) { + nsd = ques.mayUser(trans, trans.user(), newPd.value, Access.write); + } + return nsd; + } + }); + Result> nsr = ques.nsDAO.read(trans, newPd.value.ns); + if(nsr.notOKorIsEmpty()) { + return Result.err(nsr); + } + switch(fd.status) { + case OK: + Result rfc = func.createFuture(trans,fd.value, + newPd.value.fullType() + '|' + newPd.value.instance + '|' + newPd.value.action, + trans.user(), + nsr.value.get(0), + FUTURE_OP.C); + if(rfc.isOK()) { + return Result.err(Status.ACC_Future, "Perm [%s.%s|%s|%s] is saved for future processing", + newPd.value.ns, + newPd.value.type, + newPd.value.instance, + newPd.value.action); + } else { + return Result.err(rfc); + } + case Status.ACC_Now: + return func.createPerm(trans, newPd.value, true); + default: + return Result.err(fd); + } + } + + @ApiDoc( + method = GET, + path = "/authz/perms/:type", + params = {"type|string|true"}, + expectedCode = 200, + errorCodes = { 404,406 }, + text = { "List All Permissions that match the :type element of the key" } + ) + @Override + public Result getPermsByType(AuthzTrans trans, final String permType) { + final Validator v = new ServiceValidator(); + if(v.nullOrBlank("PermType", permType).err()) { + return Result.err(Status.ERR_BadData,v.errs()); + } + + Result> rlpd = ques.getPermsByType(trans, permType); + if(rlpd.notOK()) { + return Result.err(rlpd); + } + +// We don't have instance & action for mayUserView... do we want to loop through all returned here as well as in mapper? +// Result r; +// if((r = ques.mayUserViewPerm(trans, trans.user(), permType)).notOK())return Result.err(r); + + PERMS perms = mapper.newInstance(API.PERMS); + if(!rlpd.isEmpty()) { + // Note: Mapper will restrict what can be viewed + return mapper.perms(trans, rlpd.value, perms, true); + } + return Result.ok(perms); + } + + @ApiDoc( + method = GET, + path = "/authz/perms/:type/:instance/:action", + params = {"type|string|true", + "instance|string|true", + "action|string|true"}, + expectedCode = 200, + errorCodes = { 404,406 }, + text = { "List Permissions that match key; :type, :instance and :action" } + ) + @Override + public Result getPermsByName(AuthzTrans trans, String type, String instance, String action) { + final Validator v = new ServiceValidator(); + if(v.nullOrBlank("PermType", type).err() + || v.nullOrBlank("PermInstance", instance).err() + || v.nullOrBlank("PermAction", action).err()) { + return Result.err(Status.ERR_BadData,v.errs()); + } + + Result> rlpd = ques.getPermsByName(trans, type, instance, action); + if(rlpd.notOK()) { + return Result.err(rlpd); + } + + PERMS perms = mapper.newInstance(API.PERMS); + if(!rlpd.isEmpty()) { + // Note: Mapper will restrict what can be viewed + return mapper.perms(trans, rlpd.value, perms, true); + } + return Result.ok(perms); + } + + @ApiDoc( + method = GET, + path = "/authz/perms/user/:user", + params = {"user|string|true"}, + expectedCode = 200, + errorCodes = { 404,406 }, + text = { "List All Permissions that match user :user", + "

    'user' must be expressed as full identity (ex: id@full.domain.com)

    "} + ) + @Override + public Result getPermsByUser(AuthzTrans trans, String user) { + final Validator v = new ServiceValidator(); + if(v.nullOrBlank("User", user).err()) { + return Result.err(Status.ERR_BadData,v.errs()); + } + + Result> rlpd = ques.getPermsByUser(trans, user, + trans.requested(force)); + if(rlpd.notOK()) { + return Result.err(rlpd); + } + + PERMS perms = mapper.newInstance(API.PERMS); + + if(rlpd.isEmpty()) { + return Result.ok(perms); + } + // Note: Mapper will restrict what can be viewed + // if user is the same as that which is looked up, no filtering is required + return mapper.perms(trans, rlpd.value, + perms, + !user.equals(trans.user())); + } + + @ApiDoc( + method = GET, + path = "/authz/perms/user/:user/scope/:scope", + params = {"user|string|true","scope|string|true"}, + expectedCode = 200, + errorCodes = { 404,406 }, + text = { "List All Permissions that match user :user, filtered by NS (Scope)", + "

    'user' must be expressed as full identity (ex: id@full.domain.com)

    ", + "

    'scope' must be expressed as NSs separated by ':'

    " + } + ) + @Override + public Result getPermsByUserScope(AuthzTrans trans, String user, String[] scopes) { + final Validator v = new ServiceValidator(); + if(v.nullOrBlank("User", user).err()) { + return Result.err(Status.ERR_BadData,v.errs()); + } + + Result> rlpd = ques.getPermsByUser(trans, user, trans.requested(force)); + if(rlpd.notOK()) { + return Result.err(rlpd); + } + + PERMS perms = mapper.newInstance(API.PERMS); + + if(rlpd.isEmpty()) { + return Result.ok(perms); + } + // Note: Mapper will restrict what can be viewed + // if user is the same as that which is looked up, no filtering is required + return mapper.perms(trans, rlpd.value, + perms, + scopes, + !user.equals(trans.user())); + } + + @ApiDoc( + method = POST, + path = "/authz/perms/user/:user", + params = {"user|string|true"}, + expectedCode = 200, + errorCodes = { 404,406 }, + text = { "List All Permissions that match user :user", + "

    'user' must be expressed as full identity (ex: id@full.domain.com)

    ", + "", + "Present Queries as one or more Permissions (see ContentType Links below for format).", + "", + "If the Caller is Granted this specific Permission, and the Permission is valid", + " for the User, it will be included in response Permissions, along with", + " all the normal permissions on the 'GET' version of this call. If it is not", + " valid, or Caller does not have permission to see, it will be removed from the list", + "", + " *Note: This design allows you to make one call for all expected permissions", + " The permission to be included MUST be:", + " .access|:[:key]|", + " examples:", + " com.att.myns.access|:ns|write", + " com.att.myns.access|:role:myrole|create", + " com.att.myns.access|:perm:mytype:myinstance:myaction|read", + "" + } + ) + @Override + public Result getPermsByUser(AuthzTrans trans, PERMS _perms, String user) { + PERMS perms = _perms; + final Validator v = new ServiceValidator(); + if(v.nullOrBlank("User", user).err()) { + return Result.err(Status.ERR_BadData,v.errs()); + } + + ////////////// + Result> rlpd = ques.getPermsByUser(trans, user,trans.requested(force)); + if(rlpd.notOK()) { + return Result.err(rlpd); + } + + /*//TODO + 1) See if allowed to query + 2) See if User is allowed + */ + Result> in = mapper.perms(trans, perms); + if(in.isOKhasData()) { + List out = rlpd.value; + boolean ok; + for(PermDAO.Data pdd : in.value) { + ok = false; + if("access".equals(pdd.type)) { + Access access = Access.valueOf(pdd.action); + String[] mdkey = Split.splitTrim(':',pdd.instance); + if(mdkey.length>1) { + String type = mdkey[1]; + if("role".equals(type)) { + if(mdkey.length>2) { + RoleDAO.Data rdd = new RoleDAO.Data(); + rdd.ns=pdd.ns; + rdd.name=mdkey[2]; + ok = ques.mayUser(trans, trans.user(), rdd, Access.read).isOK() && ques.mayUser(trans, user, rdd , access).isOK(); + } + } else if("perm".equals(type)) { + if(mdkey.length>4) { // also need instance/action + PermDAO.Data p = new PermDAO.Data(); + p.ns=pdd.ns; + p.type=mdkey[2]; + p.instance=mdkey[3]; + p.action=mdkey[4]; + ok = ques.mayUser(trans, trans.user(), p, Access.read).isOK() && ques.mayUser(trans, user, p , access).isOK(); + } + } else if("ns".equals(type)) { + NsDAO.Data ndd = new NsDAO.Data(); + ndd.name=pdd.ns; + ok = ques.mayUser(trans, trans.user(), ndd, Access.read).isOK() && ques.mayUser(trans, user, ndd , access).isOK(); + } + } + } + if(ok) { + out.add(pdd); + } + } + } + + perms = mapper.newInstance(API.PERMS); + if(rlpd.isEmpty()) { + return Result.ok(perms); + } + // Note: Mapper will restrict what can be viewed + // if user is the same as that which is looked up, no filtering is required + return mapper.perms(trans, rlpd.value, + perms, + !user.equals(trans.user())); + } + + @ApiDoc( + method = GET, + path = "/authz/perms/role/:role", + params = {"role|string|true"}, + expectedCode = 200, + errorCodes = { 404,406 }, + text = { "List All Permissions that are granted to :role" } + ) + @Override + public Result getPermsByRole(AuthzTrans trans,String role) { + final Validator v = new ServiceValidator(); + if(v.nullOrBlank("Role", role).err()) { + return Result.err(Status.ERR_BadData,v.errs()); + } + + Result rrdd = RoleDAO.Data.decode(trans, ques,role); + if(rrdd.notOK()) { + return Result.err(rrdd); + } + + Result r = ques.mayUser(trans, trans.user(), rrdd.value, Access.read); + if(r.notOK()) { + return Result.err(r); + } + + PERMS perms = mapper.newInstance(API.PERMS); + + Result> rlpd = ques.getPermsByRole(trans, role, trans.requested(force)); + if(rlpd.isOKhasData()) { + // Note: Mapper will restrict what can be viewed + return mapper.perms(trans, rlpd.value, perms, true); + } + return Result.ok(perms); + } + + @ApiDoc( + method = GET, + path = "/authz/perms/ns/:ns", + params = {"ns|string|true"}, + expectedCode = 200, + errorCodes = { 404,406 }, + text = { "List All Permissions that are in Namespace :ns" } + ) + @Override + public Result getPermsByNS(AuthzTrans trans,String ns) { + final Validator v = new ServiceValidator(); + if(v.nullOrBlank("NS", ns).err()) { + return Result.err(Status.ERR_BadData,v.errs()); + } + + Result rnd = ques.deriveNs(trans, ns); + if(rnd.notOK()) { + return Result.err(rnd); + } + + rnd = ques.mayUser(trans, trans.user(), rnd.value, Access.read); + if(rnd.notOK()) { + return Result.err(rnd); + } + + Result> rlpd = ques.permDAO.readNS(trans, ns); + if(rlpd.notOK()) { + return Result.err(rlpd); + } + + PERMS perms = mapper.newInstance(API.PERMS); + if(!rlpd.isEmpty()) { + // Note: Mapper will restrict what can be viewed + return mapper.perms(trans, rlpd.value,perms, true); + } + return Result.ok(perms); + } + + @ApiDoc( + method = PUT, + path = "/authz/perm/:type/:instance/:action", + params = {"type|string|true", + "instance|string|true", + "action|string|true"}, + expectedCode = 200, + errorCodes = { 404,406, 409 }, + text = { "Rename the Permission referenced by :type :instance :action, and " + + "rename (copy/delete) to the Permission described in PermRequest" } + ) + @Override + public Result renamePerm(final AuthzTrans trans,REQUEST rreq, String origType, String origInstance, String origAction) { + final Result newPd = mapper.perm(trans, rreq); + final ServiceValidator v = new ServiceValidator(); + if(v.perm(newPd).err()) { + return Result.err(Status.ERR_BadData,v.errs()); + } + + if (ques.mayUser(trans, trans.user(), newPd.value,Access.write).notOK()) { + return Result.err(Status.ERR_Denied, "You do not have approval to change Permission [%s.%s|%s|%s]", + newPd.value.ns,newPd.value.type,newPd.value.instance,newPd.value.action); + } + + Result nss = ques.deriveNsSplit(trans, origType); + Result> origRlpd = ques.permDAO.read(trans, nss.value.ns, nss.value.name, origInstance, origAction); + + if(origRlpd.notOKorIsEmpty()) { + return Result.err(Status.ERR_PermissionNotFound, + "Permission [%s|%s|%s] does not exist", + origType,origInstance,origAction); + } + + PermDAO.Data origPd = origRlpd.value.get(0); + + if (!origPd.ns.equals(newPd.value.ns)) { + return Result.err(Status.ERR_Denied, "Cannot change namespace with rename command. " + + " must start with [" + origPd.ns + "]"); + } + + if ( origPd.type.equals(newPd.value.type) && + origPd.action.equals(newPd.value.action) && + origPd.instance.equals(newPd.value.instance) ) { + return Result.err(Status.ERR_ConflictAlreadyExists, "New Permission must be different than original permission"); + } + + Set origRoles = origPd.roles(false); + if (!origRoles.isEmpty()) { + Set roles = newPd.value.roles(true); + for (String role : origPd.roles) { + roles.add(role); + } + } + + newPd.value.description = origPd.description; + + Result rv = null; + + rv = func.createPerm(trans, newPd.value, false); + if (rv.isOK()) { + rv = func.deletePerm(trans, origPd, true, false); + } + return rv; + } + + @ApiDoc( + method = PUT, + path = "/authz/perm", + params = {}, + expectedCode = 200, + errorCodes = { 404,406 }, + text = { "Add Description Data to Perm" } + ) + @Override + public Result updatePermDescription(AuthzTrans trans, REQUEST from) { + final Result pd = mapper.perm(trans, from); + final ServiceValidator v = new ServiceValidator(); + if(v.perm(pd).err()) { + return Result.err(Status.ERR_BadData,v.errs()); + } + if(v.nullOrBlank("description", pd.value.description).err()) { + return Result.err(Status.ERR_BadData,v.errs()); + } + final PermDAO.Data perm = pd.value; + if(ques.permDAO.read(trans, perm.ns, perm.type, perm.instance,perm.action).notOKorIsEmpty()) { + return Result.err(Status.ERR_NotFound, "Permission [%s.%s|%s|%s] does not exist", + perm.ns,perm.type,perm.instance,perm.action); + } + + if (ques.mayUser(trans, trans.user(), perm, Access.write).notOK()) { + return Result.err(Status.ERR_Denied, "You do not have approval to change Permission [%s.%s|%s|%s]", + perm.ns,perm.type,perm.instance,perm.action); + } + + Result> nsr = ques.nsDAO.read(trans, pd.value.ns); + if(nsr.notOKorIsEmpty()) { + return Result.err(nsr); + } + + Result rdr = ques.permDAO.addDescription(trans, perm.ns, perm.type, perm.instance, + perm.action, perm.description); + if(rdr.isOK()) { + return Result.ok(); + } else { + return Result.err(rdr); + } + + } + + @ApiDoc( + method = PUT, + path = "/authz/role/perm", + params = {}, + expectedCode = 201, + errorCodes = {403,404,406,409}, + text = { "Set a permission's roles to roles given" } + ) + + @Override + public Result resetPermRoles(final AuthzTrans trans, REQUEST rreq) { + final Result updt = mapper.permFromRPRequest(trans, rreq); + if(updt.notOKorIsEmpty()) { + return Result.err(updt); + } + + final ServiceValidator v = new ServiceValidator(); + if(v.perm(updt).err()) { + return Result.err(Status.ERR_BadData,v.errs()); + } + + Result nsd = ques.mayUser(trans, trans.user(), updt.value, Access.write); + if (nsd.notOK()) { + return Result.err(nsd); + } + + // Read full set to get CURRENT values + Result> rcurr = ques.permDAO.read(trans, + updt.value.ns, + updt.value.type, + updt.value.instance, + updt.value.action); + + if(rcurr.notOKorIsEmpty()) { + return Result.err(Status.ERR_PermissionNotFound, + "Permission [%s.%s|%s|%s] does not exist", + updt.value.ns,updt.value.type,updt.value.instance,updt.value.action); + } + + // Create a set of Update Roles, which are in Internal Format + Set updtRoles = new HashSet(); + Result nss; + for(String role : updt.value.roles(false)) { + nss = ques.deriveNsSplit(trans, role); + if(nss.isOK()) { + updtRoles.add(nss.value.ns + '|' + nss.value.name); + } else { + trans.error().log(nss.errorString()); + } + } + + Result rv = null; + + for(PermDAO.Data curr : rcurr.value) { + Set currRoles = curr.roles(false); + // must add roles to this perm, and add this perm to each role + // in the update, but not in the current + for (String role : updtRoles) { + if (!currRoles.contains(role)) { + Result key = RoleDAO.Data.decode(trans, ques, role); + if(key.isOKhasData()) { + Result> rrd = ques.roleDAO.read(trans, key.value); + if(rrd.isOKhasData()) { + for(RoleDAO.Data r : rrd.value) { + rv = func.addPermToRole(trans, r, curr, false); + if (rv.notOK() && rv.status!=Result.ERR_ConflictAlreadyExists) { + return Result.err(rv); + } + } + } else { + return Result.err(rrd); + } + } + } + } + // similarly, must delete roles from this perm, and delete this perm from each role + // in the update, but not in the current + for (String role : currRoles) { + if (!updtRoles.contains(role)) { + Result key = RoleDAO.Data.decode(trans, ques, role); + if(key.isOKhasData()) { + Result> rdd = ques.roleDAO.read(trans, key.value); + if(rdd.isOKhasData()) { + for(RoleDAO.Data r : rdd.value) { + rv = func.delPermFromRole(trans, r, curr, true); + if (rv.notOK() && rv.status!=Status.ERR_PermissionNotFound) { + return Result.err(rv); + } + } + } + } + } + } + } + return rv==null?Result.ok():rv; + } + + @ApiDoc( + method = DELETE, + path = "/authz/perm", + params = {}, + expectedCode = 200, + errorCodes = { 404,406 }, + text = { "Delete the Permission referenced by PermKey.", + "You cannot normally delete a permission which is still granted to roles,", + "however the \"force\" property allows you to do just that. To do this: Add", + "'force=true' as a query parameter.", + "

    WARNING: Using force will ungrant this permission from all roles. Use with care.

    " } + ) + @Override + public Result deletePerm(final AuthzTrans trans, REQUEST from) { + Result pd = mapper.perm(trans, from); + if(pd.notOK()) { + return Result.err(pd); + } + final ServiceValidator v = new ServiceValidator(); + if(v.nullOrBlank(pd.value).err()) { + return Result.err(Status.ERR_BadData,v.errs()); + } + final PermDAO.Data perm = pd.value; + if (ques.permDAO.read(trans, perm).notOKorIsEmpty()) { + return Result.err(Status.ERR_PermissionNotFound, "Permission [%s.%s|%s|%s] does not exist", + perm.ns,perm.type,perm.instance,perm.action ); + } + + Result fd = mapper.future(trans,PermDAO.TABLE,from,perm,false, + new Mapper.Memo() { + @Override + public String get() { + return "Delete Permission [" + perm.fullPerm() + ']'; + } + }, + new MayChange() { + private Result nsd; + @Override + public Result mayChange() { + if(nsd==null) { + nsd = ques.mayUser(trans, trans.user(), perm, Access.write); + } + return nsd; + } + }); + + switch(fd.status) { + case OK: + Result> nsr = ques.nsDAO.read(trans, perm.ns); + if(nsr.notOKorIsEmpty()) { + return Result.err(nsr); + } + + Result rfc = func.createFuture(trans, fd.value, + perm.encode(), trans.user(),nsr.value.get(0),FUTURE_OP.D); + if(rfc.isOK()) { + return Result.err(Status.ACC_Future, "Perm Deletion [%s] is saved for future processing",perm.encode()); + } else { + return Result.err(rfc); + } + case Status.ACC_Now: + return func.deletePerm(trans,perm,trans.requested(force), false); + default: + return Result.err(fd); + } + } + + @ApiDoc( + method = DELETE, + path = "/authz/perm/:name/:type/:action", + params = {"type|string|true", + "instance|string|true", + "action|string|true"}, + expectedCode = 200, + errorCodes = { 404,406 }, + text = { "Delete the Permission referenced by :type :instance :action", + "You cannot normally delete a permission which is still granted to roles,", + "however the \"force\" property allows you to do just that. To do this: Add", + "'force=true' as a query parameter", + "

    WARNING: Using force will ungrant this permission from all roles. Use with care.

    "} + ) + @Override + public Result deletePerm(AuthzTrans trans, String type, String instance, String action) { + final Validator v = new ServiceValidator(); + if(v.nullOrBlank("Type",type) + .nullOrBlank("Instance",instance) + .nullOrBlank("Action",action) + .err()) { + return Result.err(Status.ERR_BadData,v.errs()); + } + + Result pd = ques.permFrom(trans, type, instance, action); + if(pd.isOK()) { + return func.deletePerm(trans, pd.value, trans.requested(force), false); + } else { + return Result.err(pd); + } + } + +/*********************************** + * ROLE + ***********************************/ + @ApiDoc( + method = POST, + path = "/authz/role", + params = {}, + expectedCode = 201, + errorCodes = {403,404,406,409}, + text = { + + "Roles are part of Namespaces", + "Examples:", + "