From 476aba57687abf592853c478775f34899aff21d9 Mon Sep 17 00:00:00 2001 From: Kiran Date: Thu, 8 Feb 2018 14:11:44 -0800 Subject: Refactor code and cleanup with stub completion Refactored code and moved some structs from handler to backend Completed the interface that is part of the backend Currently, the interface implementation is empty and will need to be fleshed out Issue-ID: AAF-99 Change-Id: I0083bc9d7ce7f6e5294339bf1e270b90c1b3de29 Signed-off-by: Kiran --- LICENSE.txt | 18 + sms-service/doc/api_swagger.yaml | 588 +++++++++++++++++++++++++++++ sms-service/doc/swagger.yaml | 588 ----------------------------- sms-service/src/sms/backend/backend.go | 50 ++- sms-service/src/sms/backend/vault.go | 95 +++++ sms-service/src/sms/backend/vault/vault.go | 56 --- sms-service/src/sms/config/config.go | 9 +- sms-service/src/sms/handler/handler.go | 105 ++++-- sms-service/src/sms/sms.go | 13 +- 9 files changed, 821 insertions(+), 701 deletions(-) create mode 100644 LICENSE.txt create mode 100644 sms-service/doc/api_swagger.yaml delete mode 100644 sms-service/doc/swagger.yaml create mode 100644 sms-service/src/sms/backend/vault.go delete mode 100644 sms-service/src/sms/backend/vault/vault.go diff --git a/LICENSE.txt b/LICENSE.txt new file mode 100644 index 0000000..5f63bb7 --- /dev/null +++ b/LICENSE.txt @@ -0,0 +1,18 @@ + + ============LICENSE_START========================================== + =================================================================== + Copyright © 2018 Intel Corp, Inc + All rights reserved. + =================================================================== + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + ============LICENSE_END============================================ diff --git a/sms-service/doc/api_swagger.yaml b/sms-service/doc/api_swagger.yaml new file mode 100644 index 0000000..c1fb634 --- /dev/null +++ b/sms-service/doc/api_swagger.yaml @@ -0,0 +1,588 @@ +swagger: "2.0" +info: + description: "This is a service that provides secret management facilities" + version: "1.0.0" + title: "Secret Management Service" + contact: + email: "kiran.k.kamineni@intel.com" + license: + name: "Apache 2.0" + url: "http://www.apache.org/licenses/LICENSE-2.0.html" +host: "aaf.onap.org:8000" +basePath: "/v1/sms/" +tags: +- name: "domain" + description: "Operations related to Secret Domains" + externalDocs: + description: "Find out more" + url: "http://swagger.io" +- name: "secret" + description: "Operations related to Secrets" +schemes: +- "https" +paths: + /domain: + post: + tags: + - "domain" + summary: "Add a new domain" + description: "" + operationId: "addDomain" + consumes: + - "application/json" + produces: + - "application/json" + parameters: + - in: "body" + name: "body" + required: true + schema: + $ref: "#/definitions/Domain" + responses: + 405: + description: "Invalid input" + 200: + description: "Successful Creation" + schema: + $ref: "#/definitions/Domain" + /domain/{domain_name}: + get: + tags: + - "domain" + summary: "Gets domain by name" + description: "Multiple status values can be provided with comma separated strings" + operationId: "findPetsByStatus" + produces: + - "application/xml" + - "application/json" + parameters: + - name: "status" + in: "query" + description: "Status values that need to be considered for filter" + required: true + type: "array" + items: + type: "string" + enum: + - "available" + - "pending" + - "sold" + default: "available" + collectionFormat: "multi" + responses: + 200: + description: "successful operation" + schema: + type: "array" + items: + $ref: "#/definitions/Pet" + 400: + description: "Invalid status value" + security: + - petstore_auth: + - "write:pets" + - "read:pets" + /pet/findByTags: + get: + tags: + - "pet" + summary: "Finds Pets by tags" + description: "Muliple tags can be provided with comma separated strings. Use tag1, tag2, tag3 for testing." + operationId: "findPetsByTags" + produces: + - "application/xml" + - "application/json" + parameters: + - name: "tags" + in: "query" + description: "Tags to filter by" + required: true + type: "array" + items: + type: "string" + collectionFormat: "multi" + responses: + 200: + description: "successful operation" + schema: + type: "array" + items: + $ref: "#/definitions/Pet" + 400: + description: "Invalid tag value" + security: + - petstore_auth: + - "write:pets" + - "read:pets" + deprecated: true + /{domainName}/{secretName}: + get: + tags: + - "secret" + summary: "Find Secret by Name" + description: "Returns a single secret" + operationId: "getSecretByName" + produces: + - "application/json" + parameters: + - name: "domainName" + in: "path" + description: "Name of the domain in which to look at" + required: true + type: "string" + - name: "secretName" + in: "path" + description: "Name of the secret which is needed" + required: true + type: "string" + responses: + 200: + description: "successful operation" + schema: + $ref: "#/definitions/Secret" + 404: + description: "Invalid Path or Path not found" + security: + - api_key: [] + delete: + tags: + - "secret" + summary: "Deletes a Secret" + description: "" + operationId: "deleteSecret" + produces: + - "application/json" + parameters: + - name: "token" + in: "header" + required: true + type: "string" + - name: "secretName" + in: "path" + description: "Name of Secret to Delete" + required: true + type: "string" + - name: "domainName" + in: "path" + description: "Path to the SecretDomain which contains the Secret" + type: "string" + responses: + 204: + description: "Successful Deletion" + 404: + description: "Invalid Path or Path not found" + /pet/{petId}/uploadImage: + post: + tags: + - "pet" + summary: "uploads an image" + description: "" + operationId: "uploadFile" + consumes: + - "multipart/form-data" + produces: + - "application/json" + parameters: + - name: "petId" + in: "path" + description: "ID of pet to update" + required: true + type: "integer" + format: "int64" + - name: "additionalMetadata" + in: "formData" + description: "Additional data to pass to server" + required: false + type: "string" + - name: "file" + in: "formData" + description: "file to upload" + required: false + type: "file" + responses: + 200: + description: "successful operation" + schema: + $ref: "#/definitions/ApiResponse" + security: + - petstore_auth: + - "write:pets" + - "read:pets" + /store/inventory: + get: + tags: + - "store" + summary: "Returns pet inventories by status" + description: "Returns a map of status codes to quantities" + operationId: "getInventory" + produces: + - "application/json" + parameters: [] + responses: + 200: + description: "successful operation" + schema: + type: "object" + additionalProperties: + type: "integer" + format: "int32" + security: + - api_key: [] + /store/order: + post: + tags: + - "store" + summary: "Place an order for a pet" + description: "" + operationId: "placeOrder" + produces: + - "application/xml" + - "application/json" + parameters: + - in: "body" + name: "body" + description: "order placed for purchasing the pet" + required: true + schema: + $ref: "#/definitions/Order" + responses: + 200: + description: "successful operation" + schema: + $ref: "#/definitions/Order" + 400: + description: "Invalid Order" + /store/order/{orderId}: + get: + tags: + - "store" + summary: "Find purchase order by ID" + description: "For valid response try integer IDs with value >= 1 and <= 10. Other values will generated exceptions" + operationId: "getOrderById" + produces: + - "application/xml" + - "application/json" + parameters: + - name: "orderId" + in: "path" + description: "ID of pet that needs to be fetched" + required: true + type: "integer" + maximum: 10.0 + minimum: 1.0 + format: "int64" + responses: + 200: + description: "successful operation" + schema: + $ref: "#/definitions/Order" + 400: + description: "Invalid ID supplied" + 404: + description: "Order not found" + delete: + tags: + - "store" + summary: "Delete purchase order by ID" + description: "For valid response try integer IDs with positive integer value. Negative or non-integer values will generate API errors" + operationId: "deleteOrder" + produces: + - "application/xml" + - "application/json" + parameters: + - name: "orderId" + in: "path" + description: "ID of the order that needs to be deleted" + required: true + type: "integer" + minimum: 1.0 + format: "int64" + responses: + 400: + description: "Invalid ID supplied" + 404: + description: "Order not found" + /user: + post: + tags: + - "user" + summary: "Create user" + description: "This can only be done by the logged in user." + operationId: "createUser" + produces: + - "application/xml" + - "application/json" + parameters: + - in: "body" + name: "body" + description: "Created user object" + required: true + schema: + $ref: "#/definitions/User" + responses: + default: + description: "successful operation" + /user/createWithArray: + post: + tags: + - "user" + summary: "Creates list of users with given input array" + description: "" + operationId: "createUsersWithArrayInput" + produces: + - "application/xml" + - "application/json" + parameters: + - in: "body" + name: "body" + description: "List of user object" + required: true + schema: + type: "array" + items: + $ref: "#/definitions/User" + responses: + default: + description: "successful operation" + /user/createWithList: + post: + tags: + - "user" + summary: "Creates list of users with given input array" + description: "" + operationId: "createUsersWithListInput" + produces: + - "application/xml" + - "application/json" + parameters: + - in: "body" + name: "body" + description: "List of user object" + required: true + schema: + type: "array" + items: + $ref: "#/definitions/User" + responses: + default: + description: "successful operation" + /user/login: + get: + tags: + - "user" + summary: "Logs user into the system" + description: "" + operationId: "loginUser" + produces: + - "application/xml" + - "application/json" + parameters: + - name: "username" + in: "query" + description: "The user name for login" + required: true + type: "string" + - name: "password" + in: "query" + description: "The password for login in clear text" + required: true + type: "string" + responses: + 200: + description: "successful operation" + schema: + type: "string" + headers: + X-Rate-Limit: + type: "integer" + format: "int32" + description: "calls per hour allowed by the user" + X-Expires-After: + type: "string" + format: "date-time" + description: "date in UTC when token expires" + 400: + description: "Invalid username/password supplied" + /user/logout: + get: + tags: + - "user" + summary: "Logs out current logged in user session" + description: "" + operationId: "logoutUser" + produces: + - "application/xml" + - "application/json" + parameters: [] + responses: + default: + description: "successful operation" + /user/{username}: + get: + tags: + - "user" + summary: "Get user by user name" + description: "" + operationId: "getUserByName" + produces: + - "application/xml" + - "application/json" + parameters: + - name: "username" + in: "path" + description: "The name that needs to be fetched. Use user1 for testing. " + required: true + type: "string" + responses: + 200: + description: "successful operation" + schema: + $ref: "#/definitions/User" + 400: + description: "Invalid username supplied" + 404: + description: "User not found" + put: + tags: + - "user" + summary: "Updated user" + description: "This can only be done by the logged in user." + operationId: "updateUser" + produces: + - "application/xml" + - "application/json" + parameters: + - name: "username" + in: "path" + description: "name that need to be updated" + required: true + type: "string" + - in: "body" + name: "body" + description: "Updated user object" + required: true + schema: + $ref: "#/definitions/User" + responses: + 400: + description: "Invalid user supplied" + 404: + description: "User not found" + delete: + tags: + - "user" + summary: "Delete user" + description: "This can only be done by the logged in user." + operationId: "deleteUser" + produces: + - "application/xml" + - "application/json" + parameters: + - name: "username" + in: "path" + description: "The name that needs to be deleted" + required: true + type: "string" + responses: + 400: + description: "Invalid username supplied" + 404: + description: "User not found" +securityDefinitions: + petstore_auth: + type: "oauth2" + authorizationUrl: "http://petstore.swagger.io/oauth/dialog" + flow: "implicit" + scopes: + write:pets: "modify pets in your account" + read:pets: "read your pets" + api_key: + type: "apiKey" + name: "api_key" + in: "header" +definitions: + Domain: + type: "object" + properties: + uuid: + type: "string" + description: "Optional value provided by user. If user does not provide, server will auto generate" + name: + type: "string" + description: "Name of the secret domain under which all secrets will be stored" + Secret: + type: "object" + properties: + name: + type: "string" + description: "Name of the secret" + value: + type: "array" + description: "Array of key value pairs that constitute the secret" + items: + type: "object" + properties: + key: + type: "string" + value: + type: "string" + Tag: + type: "object" + properties: + id: + type: "integer" + format: "int64" + name: + type: "string" + xml: + name: "Tag" + Pet: + type: "object" + required: + - "name" + - "photoUrls" + properties: + id: + type: "integer" + format: "int64" + category: + $ref: "#/definitions/Category" + name: + type: "string" + example: "doggie" + photoUrls: + type: "array" + xml: + name: "photoUrl" + wrapped: true + items: + type: "string" + tags: + type: "array" + xml: + name: "tag" + wrapped: true + items: + $ref: "#/definitions/Tag" + status: + type: "string" + description: "pet status in the store" + enum: + - "available" + - "pending" + - "sold" + xml: + name: "Pet" + ApiResponse: + type: "object" + properties: + code: + type: "integer" + format: "int32" + type: + type: "string" + message: + type: "string" +externalDocs: + description: "Find out more about Swagger" + url: "http://swagger.io" \ No newline at end of file diff --git a/sms-service/doc/swagger.yaml b/sms-service/doc/swagger.yaml deleted file mode 100644 index c1fb634..0000000 --- a/sms-service/doc/swagger.yaml +++ /dev/null @@ -1,588 +0,0 @@ -swagger: "2.0" -info: - description: "This is a service that provides secret management facilities" - version: "1.0.0" - title: "Secret Management Service" - contact: - email: "kiran.k.kamineni@intel.com" - license: - name: "Apache 2.0" - url: "http://www.apache.org/licenses/LICENSE-2.0.html" -host: "aaf.onap.org:8000" -basePath: "/v1/sms/" -tags: -- name: "domain" - description: "Operations related to Secret Domains" - externalDocs: - description: "Find out more" - url: "http://swagger.io" -- name: "secret" - description: "Operations related to Secrets" -schemes: -- "https" -paths: - /domain: - post: - tags: - - "domain" - summary: "Add a new domain" - description: "" - operationId: "addDomain" - consumes: - - "application/json" - produces: - - "application/json" - parameters: - - in: "body" - name: "body" - required: true - schema: - $ref: "#/definitions/Domain" - responses: - 405: - description: "Invalid input" - 200: - description: "Successful Creation" - schema: - $ref: "#/definitions/Domain" - /domain/{domain_name}: - get: - tags: - - "domain" - summary: "Gets domain by name" - description: "Multiple status values can be provided with comma separated strings" - operationId: "findPetsByStatus" - produces: - - "application/xml" - - "application/json" - parameters: - - name: "status" - in: "query" - description: "Status values that need to be considered for filter" - required: true - type: "array" - items: - type: "string" - enum: - - "available" - - "pending" - - "sold" - default: "available" - collectionFormat: "multi" - responses: - 200: - description: "successful operation" - schema: - type: "array" - items: - $ref: "#/definitions/Pet" - 400: - description: "Invalid status value" - security: - - petstore_auth: - - "write:pets" - - "read:pets" - /pet/findByTags: - get: - tags: - - "pet" - summary: "Finds Pets by tags" - description: "Muliple tags can be provided with comma separated strings. Use tag1, tag2, tag3 for testing." - operationId: "findPetsByTags" - produces: - - "application/xml" - - "application/json" - parameters: - - name: "tags" - in: "query" - description: "Tags to filter by" - required: true - type: "array" - items: - type: "string" - collectionFormat: "multi" - responses: - 200: - description: "successful operation" - schema: - type: "array" - items: - $ref: "#/definitions/Pet" - 400: - description: "Invalid tag value" - security: - - petstore_auth: - - "write:pets" - - "read:pets" - deprecated: true - /{domainName}/{secretName}: - get: - tags: - - "secret" - summary: "Find Secret by Name" - description: "Returns a single secret" - operationId: "getSecretByName" - produces: - - "application/json" - parameters: - - name: "domainName" - in: "path" - description: "Name of the domain in which to look at" - required: true - type: "string" - - name: "secretName" - in: "path" - description: "Name of the secret which is needed" - required: true - type: "string" - responses: - 200: - description: "successful operation" - schema: - $ref: "#/definitions/Secret" - 404: - description: "Invalid Path or Path not found" - security: - - api_key: [] - delete: - tags: - - "secret" - summary: "Deletes a Secret" - description: "" - operationId: "deleteSecret" - produces: - - "application/json" - parameters: - - name: "token" - in: "header" - required: true - type: "string" - - name: "secretName" - in: "path" - description: "Name of Secret to Delete" - required: true - type: "string" - - name: "domainName" - in: "path" - description: "Path to the SecretDomain which contains the Secret" - type: "string" - responses: - 204: - description: "Successful Deletion" - 404: - description: "Invalid Path or Path not found" - /pet/{petId}/uploadImage: - post: - tags: - - "pet" - summary: "uploads an image" - description: "" - operationId: "uploadFile" - consumes: - - "multipart/form-data" - produces: - - "application/json" - parameters: - - name: "petId" - in: "path" - description: "ID of pet to update" - required: true - type: "integer" - format: "int64" - - name: "additionalMetadata" - in: "formData" - description: "Additional data to pass to server" - required: false - type: "string" - - name: "file" - in: "formData" - description: "file to upload" - required: false - type: "file" - responses: - 200: - description: "successful operation" - schema: - $ref: "#/definitions/ApiResponse" - security: - - petstore_auth: - - "write:pets" - - "read:pets" - /store/inventory: - get: - tags: - - "store" - summary: "Returns pet inventories by status" - description: "Returns a map of status codes to quantities" - operationId: "getInventory" - produces: - - "application/json" - parameters: [] - responses: - 200: - description: "successful operation" - schema: - type: "object" - additionalProperties: - type: "integer" - format: "int32" - security: - - api_key: [] - /store/order: - post: - tags: - - "store" - summary: "Place an order for a pet" - description: "" - operationId: "placeOrder" - produces: - - "application/xml" - - "application/json" - parameters: - - in: "body" - name: "body" - description: "order placed for purchasing the pet" - required: true - schema: - $ref: "#/definitions/Order" - responses: - 200: - description: "successful operation" - schema: - $ref: "#/definitions/Order" - 400: - description: "Invalid Order" - /store/order/{orderId}: - get: - tags: - - "store" - summary: "Find purchase order by ID" - description: "For valid response try integer IDs with value >= 1 and <= 10. Other values will generated exceptions" - operationId: "getOrderById" - produces: - - "application/xml" - - "application/json" - parameters: - - name: "orderId" - in: "path" - description: "ID of pet that needs to be fetched" - required: true - type: "integer" - maximum: 10.0 - minimum: 1.0 - format: "int64" - responses: - 200: - description: "successful operation" - schema: - $ref: "#/definitions/Order" - 400: - description: "Invalid ID supplied" - 404: - description: "Order not found" - delete: - tags: - - "store" - summary: "Delete purchase order by ID" - description: "For valid response try integer IDs with positive integer value. Negative or non-integer values will generate API errors" - operationId: "deleteOrder" - produces: - - "application/xml" - - "application/json" - parameters: - - name: "orderId" - in: "path" - description: "ID of the order that needs to be deleted" - required: true - type: "integer" - minimum: 1.0 - format: "int64" - responses: - 400: - description: "Invalid ID supplied" - 404: - description: "Order not found" - /user: - post: - tags: - - "user" - summary: "Create user" - description: "This can only be done by the logged in user." - operationId: "createUser" - produces: - - "application/xml" - - "application/json" - parameters: - - in: "body" - name: "body" - description: "Created user object" - required: true - schema: - $ref: "#/definitions/User" - responses: - default: - description: "successful operation" - /user/createWithArray: - post: - tags: - - "user" - summary: "Creates list of users with given input array" - description: "" - operationId: "createUsersWithArrayInput" - produces: - - "application/xml" - - "application/json" - parameters: - - in: "body" - name: "body" - description: "List of user object" - required: true - schema: - type: "array" - items: - $ref: "#/definitions/User" - responses: - default: - description: "successful operation" - /user/createWithList: - post: - tags: - - "user" - summary: "Creates list of users with given input array" - description: "" - operationId: "createUsersWithListInput" - produces: - - "application/xml" - - "application/json" - parameters: - - in: "body" - name: "body" - description: "List of user object" - required: true - schema: - type: "array" - items: - $ref: "#/definitions/User" - responses: - default: - description: "successful operation" - /user/login: - get: - tags: - - "user" - summary: "Logs user into the system" - description: "" - operationId: "loginUser" - produces: - - "application/xml" - - "application/json" - parameters: - - name: "username" - in: "query" - description: "The user name for login" - required: true - type: "string" - - name: "password" - in: "query" - description: "The password for login in clear text" - required: true - type: "string" - responses: - 200: - description: "successful operation" - schema: - type: "string" - headers: - X-Rate-Limit: - type: "integer" - format: "int32" - description: "calls per hour allowed by the user" - X-Expires-After: - type: "string" - format: "date-time" - description: "date in UTC when token expires" - 400: - description: "Invalid username/password supplied" - /user/logout: - get: - tags: - - "user" - summary: "Logs out current logged in user session" - description: "" - operationId: "logoutUser" - produces: - - "application/xml" - - "application/json" - parameters: [] - responses: - default: - description: "successful operation" - /user/{username}: - get: - tags: - - "user" - summary: "Get user by user name" - description: "" - operationId: "getUserByName" - produces: - - "application/xml" - - "application/json" - parameters: - - name: "username" - in: "path" - description: "The name that needs to be fetched. Use user1 for testing. " - required: true - type: "string" - responses: - 200: - description: "successful operation" - schema: - $ref: "#/definitions/User" - 400: - description: "Invalid username supplied" - 404: - description: "User not found" - put: - tags: - - "user" - summary: "Updated user" - description: "This can only be done by the logged in user." - operationId: "updateUser" - produces: - - "application/xml" - - "application/json" - parameters: - - name: "username" - in: "path" - description: "name that need to be updated" - required: true - type: "string" - - in: "body" - name: "body" - description: "Updated user object" - required: true - schema: - $ref: "#/definitions/User" - responses: - 400: - description: "Invalid user supplied" - 404: - description: "User not found" - delete: - tags: - - "user" - summary: "Delete user" - description: "This can only be done by the logged in user." - operationId: "deleteUser" - produces: - - "application/xml" - - "application/json" - parameters: - - name: "username" - in: "path" - description: "The name that needs to be deleted" - required: true - type: "string" - responses: - 400: - description: "Invalid username supplied" - 404: - description: "User not found" -securityDefinitions: - petstore_auth: - type: "oauth2" - authorizationUrl: "http://petstore.swagger.io/oauth/dialog" - flow: "implicit" - scopes: - write:pets: "modify pets in your account" - read:pets: "read your pets" - api_key: - type: "apiKey" - name: "api_key" - in: "header" -definitions: - Domain: - type: "object" - properties: - uuid: - type: "string" - description: "Optional value provided by user. If user does not provide, server will auto generate" - name: - type: "string" - description: "Name of the secret domain under which all secrets will be stored" - Secret: - type: "object" - properties: - name: - type: "string" - description: "Name of the secret" - value: - type: "array" - description: "Array of key value pairs that constitute the secret" - items: - type: "object" - properties: - key: - type: "string" - value: - type: "string" - Tag: - type: "object" - properties: - id: - type: "integer" - format: "int64" - name: - type: "string" - xml: - name: "Tag" - Pet: - type: "object" - required: - - "name" - - "photoUrls" - properties: - id: - type: "integer" - format: "int64" - category: - $ref: "#/definitions/Category" - name: - type: "string" - example: "doggie" - photoUrls: - type: "array" - xml: - name: "photoUrl" - wrapped: true - items: - type: "string" - tags: - type: "array" - xml: - name: "tag" - wrapped: true - items: - $ref: "#/definitions/Tag" - status: - type: "string" - description: "pet status in the store" - enum: - - "available" - - "pending" - - "sold" - xml: - name: "Pet" - ApiResponse: - type: "object" - properties: - code: - type: "integer" - format: "int32" - type: - type: "string" - message: - type: "string" -externalDocs: - description: "Find out more about Swagger" - url: "http://swagger.io" \ No newline at end of file diff --git a/sms-service/src/sms/backend/backend.go b/sms-service/src/sms/backend/backend.go index ceb28a4..5611f37 100644 --- a/sms-service/src/sms/backend/backend.go +++ b/sms-service/src/sms/backend/backend.go @@ -16,30 +16,50 @@ package backend -import ( - vaultwrap "sms/backend/vault" -) - -// SecretDomain struct that will be passed around between http handler -// and code that interfaces with vault +// SecretDomain is where Secrets are stored. +// A single domain can have any number of secrets type SecretDomain struct { - ID int - Name string - MountPoint string + UUID string `json:"uuid"` + Name string `json:"name"` +} + +// SecretKeyValue is building block for a Secret +type SecretKeyValue struct { + Key string `json:"name"` + Value string `json:"value"` +} + +// Secret is the struct that defines the structure of a secret +// A single Secret can have any number of SecretKeyValue pairs +type Secret struct { + Name string `json:"name"` + Values []SecretKeyValue `json:"values"` } // SecretBackend interface that will be implemented for various secret backends type SecretBackend interface { - Init() + Init() error + + GetStatus() (bool, error) + GetSecretDomain(name string) (SecretDomain, error) + GetSecret(dom string, sec string) (Secret, error) - GetStatus() bool + CreateSecretDomain(name string) (SecretDomain, error) + CreateSecret(dom string, sec Secret) (Secret, error) + + DeleteSecretDomain(name string) error + DeleteSecret(dom string, name string) error } // InitSecretBackend returns an interface implementation -func InitSecretBackend() SecretBackend { - backendImpl := &vaultwrap.Vault{} - backendImpl.Init() - return backendImpl +func InitSecretBackend() (SecretBackend, error) { + backendImpl := &Vault{} + err := backendImpl.Init() + if err != nil { + return nil, err + } + + return backendImpl, nil } // LoginBackend Interface that will be implemented for various login backends diff --git a/sms-service/src/sms/backend/vault.go b/sms-service/src/sms/backend/vault.go new file mode 100644 index 0000000..f3e2ac1 --- /dev/null +++ b/sms-service/src/sms/backend/vault.go @@ -0,0 +1,95 @@ +/* + * Copyright 2018 Intel Corporation, Inc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package backend + +import ( + vaultapi "github.com/hashicorp/vault/api" + + smsconfig "sms/config" +) + +// Vault is the main Struct used in Backend to initialize the struct +type Vault struct { + vaultClient *vaultapi.Client +} + +// Init will initialize the vault connection +// TODO: Check to see if we need to wait for vault to be running +func (v *Vault) Init() error { + vaultCFG := vaultapi.DefaultConfig() + vaultCFG.Address = smsconfig.SMSConfig.VaultAddress + + client, err := vaultapi.NewClient(vaultCFG) + if err != nil { + return err + } + + v.vaultClient = client + return nil +} + +// GetStatus returns the current seal status of vault +func (v *Vault) GetStatus() (bool, error) { + sys := v.vaultClient.Sys() + sealStatus, err := sys.SealStatus() + if err != nil { + return false, err + } + + return sealStatus.Sealed, nil +} + +// GetSecretDomain returns any information related to the secretDomain +// More information can be added in the future with updates to the struct +func (v *Vault) GetSecretDomain(name string) (SecretDomain, error) { + + return SecretDomain{}, nil +} + +// GetSecret returns a secret mounted on a particular domain name +// The secret itself is referenced via its name which translates to +// a mount path in vault +func (v *Vault) GetSecret(dom string, sec string) (Secret, error) { + + return Secret{}, nil +} + +// CreateSecretDomain mounts the kv backend on a path with the given name +func (v *Vault) CreateSecretDomain(name string) (SecretDomain, error) { + + return SecretDomain{}, nil +} + +// CreateSecret creates a secret mounted on a particular domain name +// The secret itself is mounted on a path specified by name +func (v *Vault) CreateSecret(dom string, sec Secret) (Secret, error) { + + return Secret{}, nil +} + +// DeleteSecretDomain deletes a secret domain which translates to +// an unmount operation on the given path in Vault +func (v *Vault) DeleteSecretDomain(name string) error { + + return nil +} + +// DeleteSecret deletes a secret mounted on the path provided +func (v *Vault) DeleteSecret(dom string, name string) error { + + return nil +} diff --git a/sms-service/src/sms/backend/vault/vault.go b/sms-service/src/sms/backend/vault/vault.go deleted file mode 100644 index 37cb19a..0000000 --- a/sms-service/src/sms/backend/vault/vault.go +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright 2018 Intel Corporation, Inc - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package vault - -import ( - "fmt" - "log" - - vaultapi "github.com/hashicorp/vault/api" - smsConfig "sms/config" -) - -// Vault is the main Struct used in Backend to initialize the struct -type Vault struct { - vaultClient *vaultapi.Client -} - -// Init will initialize the vault connection -// TODO: Check to see if we need to wait for vault to be running -func (v *Vault) Init() { - vaultCFG := vaultapi.DefaultConfig() - vaultCFG.Address = smsConfig.SMSConfig.VaultAddress - - client, err := vaultapi.NewClient(vaultCFG) - if err != nil { - log.Fatal(err) - } - - v.vaultClient = client -} - -// GetStatus returns the current seal status of vault -func (v *Vault) GetStatus() bool { - sys := v.vaultClient.Sys() - fmt.Println(v.vaultClient.Address()) - sealStatus, err := sys.SealStatus() - if err != nil { - log.Fatal(err) - } - - return sealStatus.Sealed -} diff --git a/sms-service/src/sms/config/config.go b/sms-service/src/sms/config/config.go index d958e15..e1c1b86 100644 --- a/sms-service/src/sms/config/config.go +++ b/sms-service/src/sms/config/config.go @@ -18,7 +18,6 @@ package config import ( "encoding/json" - "log" "os" ) @@ -34,19 +33,19 @@ type SMSConfiguration struct { var SMSConfig *SMSConfiguration // ReadConfigFile reads the specified smsConfig file to setup some env variables -func ReadConfigFile(file string) *SMSConfiguration { +func ReadConfigFile(file string) (*SMSConfiguration, error) { if SMSConfig == nil { f, err := os.Open(file) if err != nil { - log.Fatalf("Unable to find file %s", file) + return nil, err } decoder := json.NewDecoder(f) err = decoder.Decode(&SMSConfig) if err != nil { - log.Fatal(err) + return nil, err } } - return SMSConfig + return SMSConfig, nil } diff --git a/sms-service/src/sms/handler/handler.go b/sms-service/src/sms/handler/handler.go index 79b8618..1b9b869 100644 --- a/sms-service/src/sms/handler/handler.go +++ b/sms-service/src/sms/handler/handler.go @@ -18,51 +18,79 @@ package handler import ( "encoding/json" + "github.com/gorilla/mux" "net/http" "sms/backend" - - "github.com/gorilla/mux" ) -type secretDomainJSON struct { - name string +type handler struct { + secretBackend backend.SecretBackend + loginBackend backend.LoginBackend } -type secretKeyValue struct { - name string - value string -} +// createSecretDomainHandler creates a secret domain with a name provided +func (h handler) createSecretDomainHandler(w http.ResponseWriter, r *http.Request) { + var d backend.SecretDomain -type secretJSON struct { - name string - values []secretKeyValue + err := json.NewDecoder(r.Body).Decode(&d) + if err != nil { + http.Error(w, err.Error(), 400) + return + } + + h.secretBackend.CreateSecretDomain(d.Name) } -type handler struct { - secretBackend backend.SecretBackend - loginBackend backend.LoginBackend +// getSecretDomainHandler returns list of secret domains +func (h handler) getSecretDomainHandler(w http.ResponseWriter, r *http.Request) { + vars := mux.Vars(r) + domName := vars["domName"] + + h.secretBackend.GetSecretDomain(domName) + //encode data into json and return } -// GetSecretDomainHandler returns list of secret domains -func (h handler) GetSecretDomainHandler(w http.ResponseWriter, r *http.Request) { +// deleteSecretDomainHandler deletes a secret domain with the name provided +func (h handler) deleteSecretDomainHandler(w http.ResponseWriter, r *http.Request) { + vars := mux.Vars(r) + domName := vars["domName"] + h.secretBackend.DeleteSecretDomain(domName) } -// CreateSecretDomainHandler creates a secret domain with a name provided -func (h handler) CreateSecretDomainHandler(w http.ResponseWriter, r *http.Request) { - var d secretDomainJSON +// createSecretHandler handles creation of secrets on a given domain name +func (h handler) createSecretHandler(w http.ResponseWriter, r *http.Request) { + vars := mux.Vars(r) + domName := vars["domName"] - err := json.NewDecoder(r.Body).Decode(&d) + var b backend.Secret + err := json.NewDecoder(r.Body).Decode(&b) if err != nil { http.Error(w, err.Error(), 400) return } + + h.secretBackend.CreateSecret(domName, b) +} + +// getSecretHandler handles reading a secret by given domain name and secret name +func (h handler) getSecretHandler(w http.ResponseWriter, r *http.Request) { + vars := mux.Vars(r) + domName := vars["domName"] + secName := vars["secretName"] + + h.secretBackend.GetSecret(domName, secName) + //encode and return response } -// DeleteSecretDomainHandler deletes a secret domain with the ID provided -func (h handler) DeleteSecretDomainHandler(w http.ResponseWriter, r *http.Request) { +// deleteSecretHandler handles deleting a secret by given domain name and secret name +func (h handler) deleteSecretHandler(w http.ResponseWriter, r *http.Request) { + vars := mux.Vars(r) + domName := vars["domName"] + secName := vars["secretName"] + h.secretBackend.DeleteSecret(domName, secName) } // struct that tracks various status items for SMS and backend @@ -70,19 +98,24 @@ type status struct { Seal bool `json:"sealstatus"` } -// StatusHandler returns information related to SMS and SMS backend services -func (h handler) StatusHandler(w http.ResponseWriter, r *http.Request) { - s := h.secretBackend.GetStatus() +// statusHandler returns information related to SMS and SMS backend services +func (h handler) statusHandler(w http.ResponseWriter, r *http.Request) { + s, err := h.secretBackend.GetStatus() + if err != nil { + http.Error(w, err.Error(), 500) + return + } + status := status{Seal: s} - err := json.NewEncoder(w).Encode(status) + err = json.NewEncoder(w).Encode(status) if err != nil { - http.Error(w, err.Error(), 400) + http.Error(w, err.Error(), 500) return } } -// LoginHandler handles login via password and username -func (h handler) LoginHandler(w http.ResponseWriter, r *http.Request) { +// loginHandler handles login via password and username +func (h handler) loginHandler(w http.ResponseWriter, r *http.Request) { } @@ -93,13 +126,17 @@ func CreateRouter(b backend.SecretBackend) http.Handler { // Create a new mux to handle URL endpoints router := mux.NewRouter() - router.HandleFunc("/v1/sms/login", h.LoginHandler).Methods("POST") + router.HandleFunc("/v1/sms/login", h.loginHandler).Methods("POST") + + router.HandleFunc("/v1/sms/status", h.statusHandler).Methods("GET") - router.HandleFunc("/v1/sms/status", h.StatusHandler).Methods("GET") + router.HandleFunc("/v1/sms/domain", h.createSecretDomainHandler).Methods("POST") + router.HandleFunc("/v1/sms/domain/{domName}", h.getSecretDomainHandler).Methods("GET") + router.HandleFunc("/v1/sms/domain/{domName}", h.deleteSecretDomainHandler).Methods("DELETE") - router.HandleFunc("/v1/sms/domain", h.GetSecretDomainHandler).Methods("GET") - router.HandleFunc("/v1/sms/domain", h.CreateSecretDomainHandler).Methods("POST") - router.HandleFunc("/v1/sms/domain/{domName}", h.DeleteSecretDomainHandler).Methods("DELETE") + router.HandleFunc("v1/sms/domain/{domainName}/secret", h.createSecretHandler).Methods("POST") + router.HandleFunc("v1/sms/domain/{domainName}/secret/{secretName}", h.getSecretHandler).Methods("GET") + router.HandleFunc("v1/sms/domain/{domainName}/secret/{secretName}", h.deleteSecretHandler).Methods("DELETE") return router } diff --git a/sms-service/src/sms/sms.go b/sms-service/src/sms/sms.go index 8fdf399..98b2824 100644 --- a/sms-service/src/sms/sms.go +++ b/sms-service/src/sms/sms.go @@ -28,9 +28,16 @@ import ( func main() { // Read Configuration File - smsConf := smsconfig.ReadConfigFile("smsconfig.json") + smsConf, err := smsconfig.ReadConfigFile("smsconfig.json") + if err != nil { + log.Fatal(err) + } + + backendImpl, err := smsbackend.InitSecretBackend() + if err != nil { + log.Fatal(err) + } - backendImpl := smsbackend.InitSecretBackend() httpRouter := smshandler.CreateRouter(backendImpl) // TODO: Use CA certificate from AAF @@ -42,6 +49,6 @@ func main() { TLSConfig: tlsConfig, } - err := httpServer.ListenAndServeTLS(smsConf.ServerCert, smsConf.ServerKey) + err = httpServer.ListenAndServeTLS(smsConf.ServerCert, smsConf.ServerKey) log.Fatal(err) } -- cgit 1.2.3-korg