This repository has been archived by the owner on Jul 22, 2018. It is now read-only.
/
OAuthValidator.scala
124 lines (101 loc) · 4.96 KB
/
OAuthValidator.scala
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
/*
* Copyright 2010 WorldWide Conferencing, LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT 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 net.liftweb {
package oauth {
import net.liftweb.common.Full
import net.liftweb.util._
import net.liftweb.common._
import Helpers._
trait OAuthValidator {
val MIN_VERSION = 1.0
val MAX_VERSION = 1.0
val MAX_TIMESTAMP_AGE_MSEC = 5 * 60 * 1000
val SINGLE_PARAMETERS = Set(OAuthUtil.OAUTH_CONSUMER_KEY, OAuthUtil.OAUTH_TOKEN, OAuthUtil.OAUTH_TOKEN_SECRET,
OAuthUtil.OAUTH_CALLBACK, OAuthUtil.OAUTH_SIGNATURE_METHOD, OAuthUtil.OAUTH_SIGNATURE,
OAuthUtil.OAUTH_TIMESTAMP, OAuthUtil.OAUTH_NONCE, OAuthUtil.OAUTH_VERSION)
protected def oauthNonceMeta: OAuthNonceMeta
def validateMessage(message: OAuthMessage, accessor: OAuthAccessor): Box[OAuthMessage] =
(checkSingleParameters _ andThen validateVersion _ andThen validateTimestampAndNonce _
andThen validateSignature(accessor) )(Full(message))
private def checkSingleParameters(message: Box[OAuthMessage]): Box[OAuthMessage] = {
message.flatMap(msg => msg.parameters.foldLeft[Map[String, List[String]]](Map()) {
case (map, next) => map + (next.name -> (next.value :: map.getOrElse(next.name, Nil)))
}.filter{ case (name, value) => value.length < 2}.toList match {
case Nil => message
case xs =>
ParamFailure(OAuthUtil.Problems.PARAMETER_REJECTED._1, Empty, Empty ,
OAuthProblem(OAuthUtil.Problems.PARAMETER_REJECTED, for {
(name, values) <- xs
value <- values
} yield (name -> value)))
}
)}
private def validateVersion(message: Box[OAuthMessage]): Box[OAuthMessage] =
for {
msg <- message
verParam <- msg.getParameter(OAuthUtil.OAUTH_VERSION)
version <- tryo(ParseDouble(verParam.value)).filter(v => v < MIN_VERSION || MAX_VERSION < v) ?~
OAuthUtil.Problems.VERSION_REJECTED._1 ~> OAuthProblem(OAuthUtil.Problems.VERSION_REJECTED,
(OAuthUtil.ProblemParams.OAUTH_ACCEPTABLE_VERSIONS, MIN_VERSION + "-" + MAX_VERSION))
} yield msg
private def validateTimestampAndNonce(message: Box[OAuthMessage]): Box[OAuthMessage] =
for {
msg <- message
timeStampStr <- msg.getParameter(OAuthUtil.OAUTH_TIMESTAMP)
timestamp <- validateTimestamp(timeStampStr)
msg2 <- validateNonce(msg, timestamp)
} yield msg2
private def validateTimestamp(timestampStr: OAuthUtil.Parameter): Box[Long] = {
val currentTimeMsec = millis
val min = (currentTimeMsec - MAX_TIMESTAMP_AGE_MSEC + 500) / 1000L
val max = (currentTimeMsec + MAX_TIMESTAMP_AGE_MSEC + 500) / 1000L
for {
timestamp <- Helpers.asLong(timestampStr.value) ?~ OAuthUtil.Problems.PARAMETER_REJECTED._1 ~>
OAuthProblem(OAuthUtil.Problems.PARAMETER_REJECTED, (OAuthUtil.ProblemParams.OAUTH_PARAMETERS_REJECTED, OAuthUtil.formEncode(List(timestampStr))))
ts2 <- Full(timestamp).filter(ts => timestamp >= min || max >= timestamp) ?~
OAuthUtil.Problems.TIMESTAMP_REFUSED._1 ~>
OAuthProblem(OAuthUtil.Problems.TIMESTAMP_REFUSED,
(OAuthUtil.ProblemParams.OAUTH_ACCEPTABLE_TIMESTAMPS, min + "-" + max))
} yield timestamp
}
private def validateNonce(message: OAuthMessage, timestamp: Long): Box[OAuthMessage] =
for {
consumerKey <- message.getConsumerKey
token = message.getToken.map(_.value).openOr("")
nonce <- message.getParameter(OAuthUtil.OAUTH_NONCE)
newNonce <- oauthNonceMeta.find(consumerKey.value, token, timestamp, nonce.value) match {
case Full(nonce) => ParamFailure(OAuthUtil.Problems.NONCE_USED._1, Empty, Empty, OAuthProblem(OAuthUtil.Problems.NONCE_USED))
case _ =>
Full(oauthNonceMeta.create(consumerKey.value, token, timestamp, nonce.value))
}
} yield {
val minTimestamp = (millis - MAX_TIMESTAMP_AGE_MSEC + 500) / 1000
oauthNonceMeta.bulkDelete_!!(minTimestamp)
message
}
private def validateSignature(accessor: OAuthAccessor)(message: Box[OAuthMessage]): Box[OAuthMessage] =
for {
msg <- message
one <- msg.getParameter(OAuthUtil.OAUTH_CONSUMER_KEY)
two <- msg.getParameter(OAuthUtil.OAUTH_SIGNATURE_METHOD)
three <- msg.getParameter(OAuthUtil.OAUTH_SIGNATURE)
// message.requireParameters(OAuth.OAUTH_CONSUMER_KEY, OAuth.OAUTH_SIGNATURE_METHOD, OAuth.OAUTH_SIGNATURE)
validator <- OAuthSignatureMethod.newSigner(msg, accessor)
res <- validator.validate(msg)
} yield msg
}
}
}