crypto.protocol.ScodecTokenAuthenticator.scala Maven / Gradle / Ivy
The newest version!
//: ----------------------------------------------------------------------------
//: Copyright (C) 2017 Verizon. All Rights Reserved.
//:
//: Licensed under the Apache License, Version 2.0 (the "License");
//: you may not use this file except in compliance with the License.
//: You may obtain a copy of the License at
//:
//: http://www.apache.org/licenses/LICENSE-2.0
//:
//: Unless required by applicable law or agreed to in writing, software
//: distributed under the License is distributed on an "AS IS" BASIS,
//: WITHOUT 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 nelson
package crypto
package protocol
import scodec._
import scodec.bits.BitVector
import scalaz.\/
/**
* Token authenticator that uses Scodec encoding and then base-64 encodes the
* result to a String token.
*
* @tparam A The result of successful authentication (ex: User, AccessToken)
*/
abstract class ScodecTokenAuthenticator[A] extends TokenAuthenticator[String, A] {
import ScodecTokenAuthenticator._
/**
* A codec to encode/decode tokens
*/
def codec: Codec[A]
/**
* Validate a result.
*
* This method is called at the end of the [[authenticate]] method to ensure
* that any domain rules are satisfied. For example, this can be used to
* verify that a token hasn't expired.
*
* @return an authentication failure on the left if there is an error,
* otherwise Unit on the right.
*/
def validate(a: A): AuthResult[Unit]
/**
* Decode and validate a token.
*
* @param base64Token a base-64 encoded token, as returned by the
* [[serialize]] method.
*/
def authenticate(base64Token: String): AuthResult[A] =
for {
tokenBits <- bitVectorFromBase64(base64Token)
token <- decode(tokenBits)
_ <- validate(token)
} yield token
def decode(tokenBits: BitVector): AuthResult[A] =
toAuthResult(codec.decode(tokenBits))
/**
* Serialize a token.
*
* @return an error message on the left if serialization fails, otherwise
* a base-64 endoded token on the right.
*/
def serialize(token: A): String \/ String =
codec.encode(token).fold(
error => \/.left(error.message),
bits => \/.right(bits.toBase64))
}
object ScodecTokenAuthenticator {
def toAuthResult[A](attempt: Attempt[DecodeResult[A]]): AuthResult[A] =
attempt.fold(
error => \/.left(errToAuthFailure(error)),
r => \/.right(r.value))
def errToAuthFailure(err: scodec.Err): AuthFailure = err match {
case AuthFailureErr(failure, _) => failure
case e => AuthFailure.GeneralFailure(e.messageWithContext, None)
}
/**
* Convert a base-64 String into a `BitVector` (if it's a valid base-64
* String).
*
* Scodec has a built-in method to do this, but currently its performance is
* pretty bad.
* See {{https://github.com/scodec/scodec-bits/issues/32 the GitHub issue }}.
*/
def bitVectorFromBase64(base64: String): AuthResult[BitVector] =
\/.fromTryCatchNonFatal(
BitVector.view(java.util.Base64.getDecoder.decode(base64))
).leftMap(AuthFailure.Base64DecodeFailure.apply)
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy