Skip to content

Commit

Permalink
Merge pull request #49 from hmrc/APIS-4455
Browse files Browse the repository at this point in the history
APIS-4455 First stage of discontinuation of legacy sandbox tokens.
  • Loading branch information
GurpreetBhamra authored Jul 15, 2019
2 parents f530400 + 49e937b commit 63820c4
Show file tree
Hide file tree
Showing 36 changed files with 494 additions and 336 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/*
* Copyright 2019 HM Revenue & Customs
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT 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 uk.gov.hmrc.thirdpartyapplication.config

import com.google.inject.AbstractModule
import javax.inject.{Inject, Singleton}
import uk.gov.hmrc.thirdpartyapplication.repository.ApplicationRepository

import scala.concurrent.ExecutionContext

class DropSandboxIndexModule extends AbstractModule {
override def configure(): Unit = {
bind(classOf[DropSandboxIndex]).asEagerSingleton()
}
}

@Singleton
class DropSandboxIndex @Inject()(applicationRepository: ApplicationRepository)(implicit ec: ExecutionContext) {

val indexName = "sandboxTokenClientIdIndex"
applicationRepository.collection.indexesManager.drop(indexName)

}

Original file line number Diff line number Diff line change
Expand Up @@ -87,20 +87,22 @@ class ApplicationController @Inject()(val applicationService: ApplicationService
}
}

def updateCheck(applicationId: UUID) = requiresAuthenticationForPrivilegedOrRopcApplications(applicationId).async(BodyParsers.parse.json) { implicit request =>
withJsonBody[CheckInformation] { checkInformation =>
applicationService.updateCheck(applicationId, checkInformation).map { result =>
Ok(toJson(result))
} recover recovery
}
def updateCheck(applicationId: UUID) = requiresAuthenticationForPrivilegedOrRopcApplications(applicationId).async(BodyParsers.parse.json) {
implicit request =>
withJsonBody[CheckInformation] { checkInformation =>
applicationService.updateCheck(applicationId, checkInformation).map { result =>
Ok(toJson(result))
} recover recovery
}
}

def fetch(applicationId: UUID) = Action.async {
handleOption(applicationService.fetch(applicationId))
}

def fetchCredentials(applicationId: UUID) = Action.async {
handleOption(credentialService.fetchCredentials(applicationId))
handleOption(credentialService.fetchCredentials(applicationId)
.map(_.map(ApplicationTokensResponse.apply)))
}

def fetchWso2Credentials(clientId: String) = Action.async {
Expand Down Expand Up @@ -136,7 +138,7 @@ class ApplicationController @Inject()(val applicationService: ApplicationService
def addClientSecret(applicationId: java.util.UUID) =
requiresAuthenticationForPrivilegedOrRopcApplications(applicationId).async(BodyParsers.parse.json) { implicit request =>
withJsonBody[ClientSecretRequest] { secret =>
credentialService.addClientSecret(applicationId, secret) map { tokens => Ok(toJson(tokens))
credentialService.addClientSecret(applicationId, secret) map { token => Ok(toJson(ApplicationTokensResponse(token)))
} recover {
case e: NotFoundException => handleNotFound(e.getMessage)
case _: InvalidEnumException => UnprocessableEntity(JsErrorResponse(INVALID_REQUEST_PAYLOAD, "Invalid environment"))
Expand Down Expand Up @@ -277,14 +279,15 @@ class ApplicationController @Inject()(val applicationService: ApplicationService
} recover recovery
}

def createSubscriptionForApplication(applicationId: UUID) = requiresAuthenticationForPrivilegedOrRopcApplications(applicationId).async(BodyParsers.parse.json) {
implicit request =>
withJsonBody[APIIdentifier] { api =>
subscriptionService.createSubscriptionForApplication(applicationId, api).map(_ => NoContent) recover {
case e: SubscriptionAlreadyExistsException => Conflict(JsErrorResponse(SUBSCRIPTION_ALREADY_EXISTS, e.getMessage))
} recover recovery
}
}
def createSubscriptionForApplication(applicationId: UUID) =
requiresAuthenticationForPrivilegedOrRopcApplications(applicationId).async(BodyParsers.parse.json) {
implicit request =>
withJsonBody[APIIdentifier] { api =>
subscriptionService.createSubscriptionForApplication(applicationId, api).map(_ => NoContent) recover {
case e: SubscriptionAlreadyExistsException => Conflict(JsErrorResponse(SUBSCRIPTION_ALREADY_EXISTS, e.getMessage))
} recover recovery
}
}

def removeSubscriptionForApplication(applicationId: UUID, context: String, version: String) = {
requiresAuthenticationForPrivilegedOrRopcApplications(applicationId).async { implicit request =>
Expand Down
22 changes: 22 additions & 0 deletions app/uk/gov/hmrc/thirdpartyapplication/models/AccessType.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
/*
* Copyright 2019 HM Revenue & Customs
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT 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 uk.gov.hmrc.thirdpartyapplication.models

object AccessType extends Enumeration {
type AccessType = Value
val STANDARD, PRIVILEGED, ROPC = Value
}
88 changes: 12 additions & 76 deletions app/uk/gov/hmrc/thirdpartyapplication/models/Application.scala
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import uk.gov.hmrc.thirdpartyapplication.models.Environment.Environment
import uk.gov.hmrc.thirdpartyapplication.models.RateLimitTier.{BRONZE, RateLimitTier}
import uk.gov.hmrc.thirdpartyapplication.models.Role.Role
import uk.gov.hmrc.thirdpartyapplication.models.State.{PRODUCTION, State, TESTING}
import uk.gov.hmrc.thirdpartyapplication.models.db.ApplicationData
import uk.gov.hmrc.time.DateTimeUtils

trait ApplicationRequest {
Expand Down Expand Up @@ -104,13 +105,6 @@ case class ApplicationResponse(id: UUID,
blocked: Boolean = false)

object ApplicationResponse {
private def getEnvironment(data: ApplicationData, clientId: Option[String]): Option[Environment] = {
clientId match {
case Some(data.tokens.production.clientId) => Some(Environment.PRODUCTION)
case Some(data.tokens.sandbox.clientId) => Some(Environment.SANDBOX)
case _ => None
}
}

def apply(data: ApplicationData, clientId: Option[String], trusted: Boolean): ApplicationResponse = {
val redirectUris = data.access match {
Expand Down Expand Up @@ -140,7 +134,7 @@ object ApplicationResponse {
termsAndConditionsUrl,
privacyPolicyUrl,
data.access,
getEnvironment(data, clientId),
Environment.from(data.environment),
data.state,
data.rateLimitTier.getOrElse(BRONZE),
trusted,
Expand All @@ -151,37 +145,12 @@ object ApplicationResponse {

case class PaginatedApplicationResponse(applications: Seq[ApplicationResponse], page: Int, pageSize: Int, total: Int, matching: Int)

case class ApplicationData(id: UUID,
name: String,
normalisedName: String,
collaborators: Set[Collaborator],
description: Option[String] = None,
wso2Username: String,
wso2Password: String,
wso2ApplicationName: String,
tokens: ApplicationTokens,
state: ApplicationState,
access: Access = Standard(Seq.empty, None, None),
createdOn: DateTime = DateTimeUtils.now,
lastAccess: Option[DateTime] = Some(DateTimeUtils.now),
rateLimitTier: Option[RateLimitTier] = Some(BRONZE),
environment: String = Environment.PRODUCTION.toString,
checkInformation: Option[CheckInformation] = None,
blocked: Boolean = false) {
lazy val admins = collaborators.filter(_.role == Role.ADMINISTRATOR)
}

case class PaginationTotal(total: Int)

case class PaginatedApplicationData(applications: Seq[ApplicationData], totals: Seq[PaginationTotal], matching: Seq[PaginationTotal])

case class CreateApplicationResponse(application: ApplicationResponse, totp: Option[TotpSecrets] = None)

object AccessType extends Enumeration {
type AccessType = Value
val STANDARD, PRIVILEGED, ROPC = Value
}

sealed trait Access {
val accessType: AccessType.Value
}
Expand Down Expand Up @@ -242,17 +211,6 @@ case class Wso2Api(name: String, version: String)

case class Collaborator(emailAddress: String, role: Role)

case class ApplicationTokens(production: EnvironmentToken,
sandbox: EnvironmentToken) {

def environmentToken(environment: Environment) = {
environment match {
case Environment.PRODUCTION => production
case _ => sandbox
}
}
}

case class ClientSecret(name: String,
secret: String = UUID.randomUUID().toString,
createdOn: DateTime = DateTimeUtils.now)
Expand Down Expand Up @@ -349,50 +307,28 @@ object ApplicationWithUpliftRequest {
}

object ApplicationTokensResponse {
def create(applicationTokens: ApplicationTokens): ApplicationTokensResponse = {

def apply(environmentTokenResponse: EnvironmentTokenResponse): ApplicationTokensResponse = {
ApplicationTokensResponse(
EnvironmentTokenResponse.create(applicationTokens.production),
EnvironmentTokenResponse.create(applicationTokens.sandbox)
production = environmentTokenResponse,
sandbox = EnvironmentTokenResponse.empty
)
}
}

object EnvironmentTokenResponse {
def create(environmentToken: EnvironmentToken): EnvironmentTokenResponse = {

def apply(environmentToken: EnvironmentToken): EnvironmentTokenResponse = {
EnvironmentTokenResponse(environmentToken.clientId, environmentToken.accessToken, environmentToken.clientSecrets)
}
}

object ApplicationData {

def create(application: CreateApplicationRequest,
wso2Username: String,
wso2Password: String,
wso2ApplicationName: String,
tokens: ApplicationTokens): ApplicationData = {

val applicationState = (application.environment, application.access.accessType) match {
case (Environment.SANDBOX, _) => ApplicationState(PRODUCTION)
case (_, PRIVILEGED | ROPC) => ApplicationState(PRODUCTION, application.collaborators.headOption.map(_.emailAddress))
case _ => ApplicationState(TESTING)
}

ApplicationData(
UUID.randomUUID,
application.name,
application.name.toLowerCase,
application.collaborators,
application.description,
wso2Username,
wso2Password,
wso2ApplicationName,
tokens,
applicationState,
application.access,
environment = application.environment.toString)
def empty = {
EnvironmentTokenResponse("", "", Seq())
}
}



object Wso2Api {

def create(api: APIIdentifier) = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import uk.gov.hmrc.thirdpartyapplication.controllers._
import uk.gov.hmrc.thirdpartyapplication.models.AccessType.{PRIVILEGED, ROPC, STANDARD}
import uk.gov.hmrc.thirdpartyapplication.models.OverrideType._
import uk.gov.hmrc.thirdpartyapplication.models.RateLimitTier.RateLimitTier
import uk.gov.hmrc.thirdpartyapplication.models.db.{ApplicationData, ApplicationTokens}
import uk.gov.hmrc.thirdpartyapplication.services.Wso2RestoreData

import scala.language.implicitConversions
Expand Down Expand Up @@ -216,14 +217,13 @@ object EnumJson {

def enumReads[E <: Enumeration](enum: E): Reads[E#Value] = new Reads[E#Value] {
def reads(json: JsValue): JsResult[E#Value] = json match {
case JsString(s) => {
case JsString(s) =>
try {
JsSuccess(enum.withName(s))
} catch {
case _: NoSuchElementException =>
throw new InvalidEnumException(enum.getClass.getSimpleName, s)
}
}
case _ => JsError("String value expected")
}
}
Expand All @@ -247,14 +247,13 @@ object APIStatusJson {
def reads(json: JsValue): JsResult[ApiStatus.Value] = json match {
case JsString("PROTOTYPED") => JsSuccess(ApiStatus.BETA)
case JsString("PUBLISHED") => JsSuccess(ApiStatus.STABLE)
case JsString(s) => {
case JsString(s) =>
try {
JsSuccess(ApiStatus.withName(s))
} catch {
case _: NoSuchElementException =>
JsError(s"Enumeration expected of type: ApiStatus, but it does not contain '$s'")
}
}
case _ => JsError("String value expected")
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
package uk.gov.hmrc.thirdpartyapplication.models

import javax.inject.{Inject, Singleton}
import uk.gov.hmrc.thirdpartyapplication.models.db.ApplicationData

@Singleton
class TrustedApplications @Inject()(config: TrustedApplicationsConfig) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
/*
* Copyright 2019 HM Revenue & Customs
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT 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 uk.gov.hmrc.thirdpartyapplication.models.db

import java.util.UUID

import org.joda.time.DateTime
import uk.gov.hmrc.thirdpartyapplication.models.AccessType._
import uk.gov.hmrc.thirdpartyapplication.models.RateLimitTier.{BRONZE, RateLimitTier}
import uk.gov.hmrc.thirdpartyapplication.models.State.{PRODUCTION, TESTING}
import uk.gov.hmrc.thirdpartyapplication.models._
import uk.gov.hmrc.time.DateTimeUtils

case class ApplicationData(id: UUID,
name: String,
normalisedName: String,
collaborators: Set[Collaborator],
description: Option[String] = None,
wso2Username: String,
wso2Password: String,
wso2ApplicationName: String,
tokens: ApplicationTokens,
state: ApplicationState,
access: Access = Standard(Seq.empty, None, None),
createdOn: DateTime = DateTimeUtils.now,
lastAccess: Option[DateTime] = Some(DateTimeUtils.now),
rateLimitTier: Option[RateLimitTier] = Some(BRONZE),
environment: String = Environment.PRODUCTION.toString,
checkInformation: Option[CheckInformation] = None,
blocked: Boolean = false) {
lazy val admins = collaborators.filter(_.role == Role.ADMINISTRATOR)
}

object ApplicationData {

def create(application: CreateApplicationRequest,
wso2Username: String,
wso2Password: String,
wso2ApplicationName: String,
tokens: ApplicationTokens): ApplicationData = {

val applicationState = (application.environment, application.access.accessType) match {
case (Environment.SANDBOX, _) => ApplicationState(PRODUCTION)
case (_, PRIVILEGED | ROPC) => ApplicationState(PRODUCTION, application.collaborators.headOption.map(_.emailAddress))
case _ => ApplicationState(TESTING)
}

ApplicationData(
UUID.randomUUID,
application.name,
application.name.toLowerCase,
application.collaborators,
application.description,
wso2Username,
wso2Password,
wso2ApplicationName,
tokens,
applicationState,
application.access,
environment = application.environment.toString)
}
}

case class ApplicationTokens(production: EnvironmentToken)
Loading

0 comments on commit 63820c4

Please sign in to comment.