All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.wordnik.swagger.auth.service.AuthService.scala Maven / Gradle / Ivy

The newest version!
package com.wordnik.swagger.auth.service

import com.wordnik.swagger.auth.model._
import com.wordnik.swagger.core.SwaggerContext

import org.apache.oltu.oauth2.as.request.{ OAuthAuthzRequest, OAuthTokenRequest }
import org.apache.oltu.oauth2.as.response.OAuthASResponse
import org.apache.oltu.oauth2.common.OAuth
import org.apache.oltu.oauth2.common.exception.{ OAuthProblemException, OAuthSystemException }
import org.apache.oltu.oauth2.common.message.OAuthResponse
import org.apache.oltu.oauth2.common.message.types.ResponseType
import org.apache.oltu.oauth2.common.utils.OAuthUtils

import org.slf4j.LoggerFactory

import javax.servlet.http.{ Cookie, HttpServletRequest, HttpServletResponse }

import javax.ws.rs.core.Response
import javax.ws.rs.WebApplicationException

import java.util.Date
import java.net.URLEncoder
import java.net.URI

import scala.collection.mutable.HashSet

class AuthService extends TokenStore {
  private val LOGGER = LoggerFactory.getLogger(classOf[AuthService])

  val validator = ValidatorFactory.validator

  def validate[T](accessCode: String, f: => T):T = {
    LOGGER.debug("validating access code " + accessCode)
    if(hasAccessCode(accessCode)) {
      val token = getTokenForAccessCode(accessCode)
      if(token.getRemaining > 0) {
        token.tokenResponse match {
          case e: AnonymousTokenResponse => TokenScope.unsetUsername()
          case e: UserTokenResponse => TokenScope.setUsername(e.username)
          case _ => throw new Exception("unauthorized")
        }
        f
      }
      else throw new Exception("unauthorized")
    }
    else throw new Exception("unauthorized")
  }

  def login(request: HttpServletRequest, response: HttpServletResponse) = {
    val scope = request.getParameter("scope")
    val redirectUri = request.getParameter("redirect_uri")
    val username = request.getParameter("username")
    val password = request.getParameter("password")
    val clientId = request.getParameter("client_id")
    val accept = request.getParameter("accept")
    val requestId = request.getParameter("request_id")
    val responseType = request.getParameter("response_type")

    LOGGER.debug("logging in user " + username + ", accept=" + accept)

    if(accept.toLowerCase == "deny") {
      LOGGER.debug("user " + username + " denied the login request")
      val redirectTo = {
        (redirectUri.indexOf("#") match {
          case i: Int if(i >= 0) => redirectUri + "&"
          case i: Int => redirectUri + "#"
        }) + "error=user_cancelled"
      }
      response.sendRedirect(redirectTo)
    }
    else if(validator.isValidUser(username, password)) {
      LOGGER.debug("username " + username + " has valid password")
      if(validator.isValidRedirectUri(clientId, redirectUri)) {
        LOGGER.debug("username " + username + " has valid redirect URI: " + redirectUri)
        val redirectTo = {
          (redirectUri.indexOf("?") match {
            case i: Int if(i >= 0) => redirectUri + "&"
            case i: Int => redirectUri + "?"
          })
        }
        if(requestId != null && !"".equals(requestId)) {
          LOGGER.debug("username " + username + " has request id=" + requestId)
          if(hasRequestId(requestId)) {
            LOGGER.debug("token for requestId " + requestId + " found")
            // now that we have the username, save it in the hash
            val requestToken = getRequestId(requestId) ++ Map("username" -> Some(username))
            addRequestId(requestId, requestToken)

            val redirectUri = requestToken(OAuth.OAUTH_REDIRECT_URI ).get
            val redirectTo = {
              (redirectUri.indexOf("?") match {
                case i: Int if(i >= 0) => redirectUri + "&"
                case i: Int => redirectUri + "?"
              })
            }
            val code = exchangeRequestIdForCode(requestId)
            val token = UserTokenResponse(3600, code, username)
            addAccessCode(code, TokenWrapper(new Date, token))
            LOGGER.debug("redirecting to " + redirectTo + "code=" + code)
            response.sendRedirect(redirectTo + "code=" + code)
          }
          else {
            LOGGER.debug("token for requestId " + requestId + " NOT found")
            response.sendRedirect(redirectTo + "error=invalid_code")
          }
        }
        else {
          // should this actually exist?
          LOGGER.debug("no request id, generating access token")
          val accessToken = generateAccessToken()
          val token = UserTokenResponse(3600, accessToken, username)
          addAccessCode(accessToken, TokenWrapper(new Date, token))

          val redirectTo = {
            (redirectUri.indexOf("#") match {
              case i: Int if(i >= 0) => redirectUri + "&"
              case i: Int => redirectUri + "#"
            }) + "access_token=" + accessToken
          }
          response.sendRedirect(redirectTo)
        }
      }
      else response.getOutputStream.write("bad redirect_uri".getBytes("utf-8"))
    }
    else {
      LOGGER.debug("invalid credentials")
      val redirectTo = {
        (redirectUri.indexOf("#") match {
          case i: Int if(i >= 0) => redirectUri + "&"
          case i: Int => redirectUri + "#"
        }) + "error=invalid_credentials"
      }
      response.sendRedirect(redirectTo)
    }
  }

  def authorizationCodeStatus(accessCode: String) = {
    LOGGER.debug("checking code status for " + accessCode)
    if(hasAccessCode(accessCode)) {
      val token = getTokenForAccessCode(accessCode)
      if(token.getRemaining > 0)
        ApiResponseMessage(200, "%d seconds remaining".format(token.getRemaining))
      else
        ApiResponseMessage(400, "invalid token")
    }
    else 
      ApiResponseMessage(400, "invalid token")
  }

  def token(request: HttpServletRequest, response: HttpServletResponse): TokenResponse = {
    try {
      val oauthRequest = new OAuthTokenRequest(request)
      val code = oauthRequest.getParam(OAuth.OAUTH_CODE)
      val grantType = oauthRequest.getParam(OAuth.OAUTH_GRANT_TYPE)
      val clientId = oauthRequest.getParam(OAuth.OAUTH_CLIENT_ID)
      val clientSecret = oauthRequest.getParam(OAuth.OAUTH_CLIENT_SECRET)

      LOGGER.debug("get token for '" + clientId + "'' with client secret '" + clientSecret + "'")
      if(validator.isValidClient(clientId, clientSecret)) {
        if("authorization_code" == grantType) {
          LOGGER.debug("grant type is " + grantType)
          val validCode = hasAccessCode(code)

          if(validCode) {
            val username = getTokenForAccessCode(code).tokenResponse match {
              case t: UserTokenResponse => t.username
              case _ => null
            }
            removeAccessCode(code)
            val accessToken = generateAccessToken()
            val token = UserTokenResponse(3600, accessToken, username)
            addAccessCode(accessToken, TokenWrapper(new Date, token))
            token
          }
          else if(allowAnonymousTokens()) {
            val accessToken = generateAccessToken()
            val token = AnonymousTokenResponse(3600, accessToken)
            addAccessCode(accessToken, TokenWrapper(new Date, token))
            token
          }
          else
            throw new Exception("invalid code supplied")
        }
        else {
          LOGGER.debug("unsupported grant type " + grantType)
          throw new Exception("unsupported grant type")
        }
      }
      else {
        LOGGER.debug("invalid client id " + clientId)
        throw new Exception("invalid client id")
      }
    }
    catch {
      case e: Exception => {
        throw new Exception(e.getMessage)
      }
    }
  }

  def authorize(request: HttpServletRequest,response: HttpServletResponse): ApiResponseMessage = {
    import scala.collection.JavaConverters._

    var oauthRequest: OAuthAuthzRequest = null;
    try {
      oauthRequest = new OAuthAuthzRequest(request)

      //build response according to response_type
      val responseType = oauthRequest.getParam(OAuth.OAUTH_RESPONSE_TYPE)
      val builder = OAuthASResponse.authorizationResponse(request, HttpServletResponse.SC_FOUND)

      if (responseType.equals(ResponseType.CODE.toString())) {
        val requestMap = Map(
          OAuth.OAUTH_STATE -> Option(oauthRequest.getParam(OAuth.OAUTH_STATE)),
          OAuth.OAUTH_REDIRECT_URI -> Option(oauthRequest.getParam(OAuth.OAUTH_REDIRECT_URI)),
          OAuth.OAUTH_CLIENT_ID -> Option(oauthRequest.getParam(OAuth.OAUTH_CLIENT_ID)),
          OAuth.OAUTH_SCOPE -> Option(oauthRequest.getParam(OAuth.OAUTH_SCOPE)))

        val requestId = generateRequestId(oauthRequest.getParam(OAuth.OAUTH_CLIENT_ID))
        addRequestId(requestId, requestMap)
        val dialogClass = Option(request.getSession.getServletContext.getInitParameter("DialogImplementation")).getOrElse({
          LOGGER.warn("using default dialog implementation")
          "com.wordnik.swagger.auth.service.DefaultAuthDialog"
        })
        val dialog = SwaggerContext.loadClass(dialogClass).newInstance.asInstanceOf[AuthDialog]
        // write the dialog UI
        dialog.show(oauthRequest.getParam(OAuth.OAUTH_CLIENT_ID),
          oauthRequest.getParam(OAuth.OAUTH_REDIRECT_URI),
          oauthRequest.getParam(OAuth.OAUTH_SCOPE),
          ResponseType.CODE.toString(),
          Option(requestId))
      }
      else {
        val redirectURI = oauthRequest.getParam(OAuth.OAUTH_REDIRECT_URI)
        val response = builder.location(redirectURI).buildQueryMessage()
        val url = new URI(response.getLocationUri())
        ApiResponseMessage(200, url.toString)
      }
    } catch {
      case e: OAuthProblemException => {
        e.printStackTrace();
        val responseBuilder = Response.status(HttpServletResponse.SC_FOUND)

        val redirectUri = e.getRedirectUri();

        if (OAuthUtils.isEmpty(redirectUri)) {
          ApiResponseMessage(400, "OAuth callback url needs to be provided by client")
        }
        else ApiResponseMessage(400, e.getMessage)
      }
    }
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy