Skip to content
GitLab
Projects
Groups
Snippets
Help
Loading...
Help
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
T
TOTP-Shibboleth-loginhandler
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Service Desk
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Operations
Operations
Environments
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Victor Näslund
TOTP-Shibboleth-loginhandler
Commits
cfb18f02
Commit
cfb18f02
authored
Sep 12, 2016
by
Victor Näslund
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Added project
parents
Changes
17
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
17 changed files
with
2139 additions
and
0 deletions
+2139
-0
README.md
README.md
+178
-0
pom.xml
pom.xml
+67
-0
src/main/java/se/smhi/totp/Base32String.java
src/main/java/se/smhi/totp/Base32String.java
+133
-0
src/main/java/se/smhi/totp/ExtractUsernamePasswordTOTPFromFormRequest.java
...smhi/totp/ExtractUsernamePasswordTOTPFromFormRequest.java
+192
-0
src/main/java/se/smhi/totp/PasscodeGenerator.java
src/main/java/se/smhi/totp/PasscodeGenerator.java
+213
-0
src/main/java/se/smhi/totp/TOTPAES.java
src/main/java/se/smhi/totp/TOTPAES.java
+211
-0
src/main/java/se/smhi/totp/TOTPLDAP.java
src/main/java/se/smhi/totp/TOTPLDAP.java
+159
-0
src/main/java/se/smhi/totp/TOTPReadConfigFile.java
src/main/java/se/smhi/totp/TOTPReadConfigFile.java
+60
-0
src/main/java/se/smhi/totp/TOTPThrottle.java
src/main/java/se/smhi/totp/TOTPThrottle.java
+244
-0
src/main/java/se/smhi/totp/TOTPValidate.java
src/main/java/se/smhi/totp/TOTPValidate.java
+40
-0
src/main/java/se/smhi/totp/UsernamePasswordTOTPContext.java
src/main/java/se/smhi/totp/UsernamePasswordTOTPContext.java
+103
-0
src/main/java/se/smhi/totp/ValidateUsernamePasswordTOTPAgainstLDAP.java
...se/smhi/totp/ValidateUsernamePasswordTOTPAgainstLDAP.java
+0
-0
src/main/resources/conf/authn/totp-authn-config.xml
src/main/resources/conf/authn/totp-authn-config.xml
+92
-0
src/main/resources/system/flows/authn/totp-authn-beans.xml
src/main/resources/system/flows/authn/totp-authn-beans.xml
+95
-0
src/main/resources/system/flows/authn/totp-authn-flow.xml
src/main/resources/system/flows/authn/totp-authn-flow.xml
+77
-0
src/main/resources/views/loginTOTP.vm
src/main/resources/views/loginTOTP.vm
+122
-0
src/test/java/se/smhi/totp/TOTPTest.java
src/test/java/se/smhi/totp/TOTPTest.java
+153
-0
No files found.
README.md
0 → 100644
View file @
cfb18f02
# Shibboleth-TOTP-loginhandler
This project add a TOTP loginhandler for shibboleth-idp
The TOTP secret is stored encrypted in LDAP
## How to use
First install maven and java 1.8 devel.
Then create the file /opt/shibboleth-idp/credentials/totp-configfile
both on your current compiling node and the shibboleth-idp node
```
bash
# Lines are in this format type:value
# Values are encoded in base64
#
# FirstPartOfTOTPAESKey and SecondPartOfTOTPAESKey
# will be used for the encryption key for the TOTP secrets stored in LDAP
# Fore more info about the encryption see TOTPAES.java
# Change them to something appropriate
#
# TOTPMaxTries is how many times one can try
# before the module start taking anti bruteforce measures
#
# TOTPThrottleTime is how many seconds the account and/or ip address
# will be locked because of anti bruteforce measures
#
# To encode the values to base64 use this
# echo -n "BBB" | base64
# Will give you QkJC
#
# To decode base64 do this
# echo "QkJC" | base64 -d
FirstPartOfTOTPAESKey:QUFB
SecondPartOfTOTPAESKey:QkJC
TOTPMaxTries:OA
==
TOTPThrottleTime:MTIwMA
==
```
To compile the module run
```
bash
mvn clean
install
```
This will give you a jar file
```
bash
totp-0.99.jar
```
Copy this file to your shibboleth-idp installation like
```
bash
cp
totp-0.99.jar
${
shibboleth
-idp
}
/edit-webapp/WEB-INF/lib/
```
Rebuild shibboleth-idp with the module using
```
bash
cd
${
shibboleth
-idp
}
./bin/build.sh
```
### Ok now we simply have to edit some config files to enable the module
In ${shibboleth-idp}/conf/logback.xml we have this
```
xml
<!-- Logs IdP, but not OpenSAML, messages -->
<logger
name=
"net.shibboleth.idp"
level=
"INFO"
/>
```
Add this just below
```
xml
<!-- TOTP set to DEBUG if needed -->
<logger
name=
"se.smhi.totp"
level=
"INFO"
/>
```
In ${shibboleth-idp}/conf/authn/general-authn.xml we have this
```
xml
<bean
id=
"authn/Password"
parent=
"shibboleth.AuthenticationFlow"
p:passiveAuthenticationSupported=
"true"
p:forcedAuthenticationSupported=
"true"
/>
```
Add this just below
```
xml
<!-- TOTP -->
<bean
id=
"authn/TOTP"
parent=
"shibboleth.AuthenticationFlow"
p:passiveAuthenticationSupported=
"true"
p:forcedAuthenticationSupported=
"true"
>
<property
name=
"supportedPrincipals"
>
<util:list>
<bean
parent=
"shibboleth.SAML2AuthnContextClassRef"
c:classRef=
"urn:oasis:names:tc:SAML:2.0:ac:classes:TimeSyncToken"
/>
</util:list>
</property>
</bean>
```
In ${shibboleth-idp}/conf/authn/ldap-authn-config.xml we have this line
```
xml
<alias
name=
"ValidateUsernamePasswordAgainstLDAP"
alias=
"ValidateUsernamePassword"
/>
```
Add this line below it
```
xml
<alias
name=
"ValidateUsernamePasswordTOTPAgainstLDAP"
alias=
"ValidateUsernamePasswordTOTP"
/>
```
In the file ${shibboleth-idp}/conf/ldap.properties we have idp.authn.LDAP.returnAttributes
Edit idp.authn.LDAP.returnAttributes by adding the name of your LDAP TOTP attribute here so shibboleth fetch it during authentication
Also edit TOTP to idp.authn.flows like
```
bash
idp.authn.LDAP.returnAttributes
=
cn,TOTPAttribute
idp.authn.flows
=
Password|TOTP
```
In ${shibboleth-idp}/flows/authn/conditions/conditions-flow.xml we have this
```
xml
<action-state
id=
"ValidateUsernamePassword"
>
<!-- Call outs for exceptional conditions. -->
<transition
on=
"AccountWarning"
to=
"CallExpiringPassword"
/>
<transition
on=
"ExpiringPassword"
to=
"CallExpiringPassword"
/>
<transition
on=
"ExpiredPassword"
to=
"CallExpiredPassword"
/>
<transition
on=
"AccountLocked"
to=
"CallAccountLocked"
/>
<transition
to=
"DisplayUsernamePasswordPage"
/>
</action-state>
```
Add this just below
```
xml
<!-- TOTP -->
<action-state
id=
"ValidateUsernamePasswordTOTP"
>
<!-- Call outs for exceptional conditions. -->
<transition
on=
"AccountWarning"
to=
"CallExpiringPassword"
/>
<transition
on=
"ExpiringPassword"
to=
"CallExpiringPassword"
/>
<transition
on=
"ExpiredPassword"
to=
"CallExpiredPassword"
/>
<transition
on=
"AccountLocked"
to=
"CallAccountLocked"
/>
<transition
to=
"DisplayUsernamePasswordTOTPPage"
/>
</action-state>
```
In ${shibboleth-idp}/messages/authn-messages.properties add these lines
```
bash
ThrottledUsername
=
throttled-username
ThrottledIPAddress
=
throttled-ipaddress
throttled-username.message
=
Your account is locked
for
XXX
(
see TOTPThrottle.java file
)
minutes
throttled-ipaddress.message
=
Your IP address is locked
for
XXX
(
see TOTPThrottle.java file
)
minutes
```
In the file ${shibboleth-idp}/system/conf/webflow-config.xml we have this line
```
xml
<webflow:flow-location
id=
"authn/Password"
path=
"../system/flows/authn/password-authn-flow.xml"
/>
```
Add this below it
```
xml
<!-- TOTP-->
<webflow:flow-location
id=
"authn/TOTP"
path=
"../system/flows/authn/totp-authn-flow.xml"
/>
```
Now copy the TOTP config files
```
bash
cp
system/flows/authn/totp-authn-beans.xml to
${
shibboleth
-idp
}
/system/flows/authn/totp-authn-beans.xml
cp
system/flows/authn/totp-authn-flow.xml
${
shibboleth
-idp
}
/system/flows/authn/totp-authn-flow.xml
cp
views/loginTOTP.vm
${
shibboleth
-idp
}
/views/loginTOTP.vm
cp
conf/authn/totp-authn-config.xml
${
shibboleth
-idp
}
/conf/authn/totp-authn-config.xml
```
## Generate your TOTP secret
Uncomment the function call to generateSecretSaltIvForLDAP at the end of the function testValidateTOTPCode in TOTPTest.java then
```
bash
mvn clean
install
```
Edit your LDAP multivalue attribute and add the generated encrypted secret, salt and IV to your LDAP attribute
Add the TOTP secret to your TOTP device, for example the app Google Authenticator for Android/iPhone phones
## You should now be able to login using TOTP
pom.xml
0 → 100644
View file @
cfb18f02
<project
xmlns=
"http://maven.apache.org/POM/4.0.0"
xmlns:xsi=
"http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation=
"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"
>
<modelVersion>
4.0.0
</modelVersion>
<groupId>
se.smhi.totp
</groupId>
<artifactId>
totp
</artifactId>
<packaging>
jar
</packaging>
<version>
0.99
</version>
<name>
totp
</name>
<url>
http://smhi.se
</url>
<properties>
<maven.compiler.source>
1.8
</maven.compiler.source>
<maven.compiler.target>
1.8
</maven.compiler.target>
<project.build.sourceEncoding>
UTF-8
</project.build.sourceEncoding>
</properties>
<repositories>
<repository>
<id>
shib-release
</id>
<url>
https://build.shibboleth.net/nexus/content/groups/public
</url>
<snapshots>
<enabled>
false
</enabled>
</snapshots>
</repository>
<repository>
<id>
shib-snapshot
</id>
<url>
https://build.shibboleth.net/nexus/content/repositories/snapshots
</url>
<releases>
<enabled>
false
</enabled>
</releases>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>
com.google.code.findbugs
</groupId>
<artifactId>
jsr305
</artifactId>
<version>
RELEASE
</version>
</dependency>
<dependency>
<groupId>
net.shibboleth.idp
</groupId>
<artifactId>
idp-authn-impl
</artifactId>
<version>
RELEASE
</version>
</dependency>
<dependency>
<groupId>
javax.servlet
</groupId>
<artifactId>
javax.servlet-api
</artifactId>
<version>
RELEASE
</version>
</dependency>
<dependency>
<groupId>
junit
</groupId>
<artifactId>
junit
</artifactId>
<version>
RELEASE
</version>
<scope>
test
</scope>
</dependency>
</dependencies>
</project>
src/main/java/se/smhi/totp/Base32String.java
0 → 100644
View file @
cfb18f02
package
se.smhi.totp
;
import
java.util.HashMap
;
/**
* Encodes arbitrary byte arrays as case-insensitive base-32 strings
*
* @author sweis@google.com (Steve Weis)
* @author Neal Gafter
*/
public
class
Base32String
{
// singleton
private
static
final
Base32String
INSTANCE
=
new
Base32String
(
"ABCDEFGHIJKLMNOPQRSTUVWXYZ234567"
);
// RFC 4668/3548
static
Base32String
getInstance
()
{
return
INSTANCE
;
}
//32 alpha-numeric characters. Excluding 0, 1, O, and I
private
String
ALPHABET
;
private
char
[]
DIGITS
;
private
int
MASK
;
private
int
SHIFT
;
private
HashMap
<
Character
,
Integer
>
CHAR_MAP
;
static
final
String
SEPARATOR
=
"-"
;
protected
Base32String
(
String
alphabet
)
{
this
.
ALPHABET
=
alphabet
;
DIGITS
=
ALPHABET
.
toCharArray
();
MASK
=
DIGITS
.
length
-
1
;
SHIFT
=
Integer
.
numberOfTrailingZeros
(
DIGITS
.
length
);
CHAR_MAP
=
new
HashMap
<
Character
,
Integer
>();
for
(
int
i
=
0
;
i
<
DIGITS
.
length
;
i
++)
{
CHAR_MAP
.
put
(
DIGITS
[
i
],
i
);
}
}
public
static
byte
[]
decode
(
String
encoded
)
throws
DecodingException
{
return
getInstance
().
decodeInternal
(
encoded
);
}
protected
byte
[]
decodeInternal
(
String
encoded
)
throws
DecodingException
{
// Remove whitespace and separators
encoded
=
encoded
.
trim
().
replaceAll
(
SEPARATOR
,
""
).
replaceAll
(
" "
,
""
);
// Canonicalize to all upper case
encoded
=
encoded
.
toUpperCase
();
if
(
encoded
.
length
()
==
0
)
{
return
new
byte
[
0
];
}
int
encodedLength
=
encoded
.
length
();
int
outLength
=
encodedLength
*
SHIFT
/
8
;
byte
[]
result
=
new
byte
[
outLength
];
int
buffer
=
0
;
int
next
=
0
;
int
bitsLeft
=
0
;
for
(
char
c
:
encoded
.
toCharArray
())
{
if
(!
CHAR_MAP
.
containsKey
(
c
))
{
throw
new
DecodingException
(
"Illegal character: "
+
c
);
}
buffer
<<=
SHIFT
;
buffer
|=
CHAR_MAP
.
get
(
c
)
&
MASK
;
bitsLeft
+=
SHIFT
;
if
(
bitsLeft
>=
8
)
{
result
[
next
++]
=
(
byte
)
(
buffer
>>
(
bitsLeft
-
8
));
bitsLeft
-=
8
;
}
}
// We'll ignore leftover bits for now.
//
// if (next != outLength || bitsLeft >= SHIFT) {
// throw new DecodingException("Bits left: " + bitsLeft);
// }
return
result
;
}
public
static
String
encode
(
byte
[]
data
)
{
return
getInstance
().
encodeInternal
(
data
);
}
protected
String
encodeInternal
(
byte
[]
data
)
{
if
(
data
.
length
==
0
)
{
return
""
;
}
// SHIFT is the number of bits per output character, so the length of the
// output is the length of the input multiplied by 8/SHIFT, rounded up.
if
(
data
.
length
>=
(
1
<<
28
))
{
// The computation below will fail, so don't do it.
throw
new
IllegalArgumentException
();
}
int
outputLength
=
(
data
.
length
*
8
+
SHIFT
-
1
)
/
SHIFT
;
StringBuilder
result
=
new
StringBuilder
(
outputLength
);
int
buffer
=
data
[
0
];
int
next
=
1
;
int
bitsLeft
=
8
;
while
(
bitsLeft
>
0
||
next
<
data
.
length
)
{
if
(
bitsLeft
<
SHIFT
)
{
if
(
next
<
data
.
length
)
{
buffer
<<=
8
;
buffer
|=
(
data
[
next
++]
&
0xff
);
bitsLeft
+=
8
;
}
else
{
int
pad
=
SHIFT
-
bitsLeft
;
buffer
<<=
pad
;
bitsLeft
+=
pad
;
}
}
int
index
=
MASK
&
(
buffer
>>
(
bitsLeft
-
SHIFT
));
bitsLeft
-=
SHIFT
;
result
.
append
(
DIGITS
[
index
]);
}
return
result
.
toString
();
}
@Override
// enforce that this class is a singleton
public
Object
clone
()
throws
CloneNotSupportedException
{
throw
new
CloneNotSupportedException
();
}
public
class
DecodingException
extends
Exception
{
public
DecodingException
(
String
message
)
{
super
(
message
);
}
}
}
src/main/java/se/smhi/totp/ExtractUsernamePasswordTOTPFromFormRequest.java
0 → 100644
View file @
cfb18f02
package
se.smhi.totp
;
import
javax.annotation.Nonnull
;
import
javax.servlet.http.HttpServletRequest
;
import
net.shibboleth.idp.authn.AbstractExtractionAction
;
import
net.shibboleth.idp.authn.AuthnEventIds
;
import
net.shibboleth.idp.authn.context.AuthenticationContext
;
import
net.shibboleth.utilities.java.support.annotation.constraint.NotEmpty
;
import
net.shibboleth.utilities.java.support.component.ComponentSupport
;
import
net.shibboleth.utilities.java.support.logic.Constraint
;
import
net.shibboleth.utilities.java.support.primitive.StringSupport
;
import
org.opensaml.profile.action.ActionSupport
;
import
org.opensaml.profile.context.ProfileRequestContext
;
import
org.slf4j.Logger
;
import
org.slf4j.LoggerFactory
;
/**
* SMHI 2015-11-11 Victor Näslund <victor.naslund@smhi.se>
* Modified version of net.shibboleth.idp.authn.context.UsernamePasswordContext
* Added TOTP and throttling code
*/
/**
* An action that extracts a username and password from an HTTP form body or query string,
* creates a {@link UsernamePasswordContext}, and attaches it to the {@link AuthenticationContext}.
*
* @event {@link org.opensaml.profile.action.EventIds#PROCEED_EVENT_ID}
* @event {@link AuthnEventIds#NO_CREDENTIALS}
* @pre <pre>ProfileRequestContext.getSubcontext(AuthenticationContext.class, false) != null</pre>
* @post If getHttpServletRequest() != null, a pair of form or query parameters is
* extracted to populate a {@link UsernamePasswordContext}.
*/
public
class
ExtractUsernamePasswordTOTPFromFormRequest
extends
AbstractExtractionAction
{
/** Class logger. */
@Nonnull
private
final
Logger
log
=
LoggerFactory
.
getLogger
(
ExtractUsernamePasswordTOTPFromFormRequest
.
class
);
/** Parameter name for TOTPCode. */
@Nonnull
@NotEmpty
private
String
TOTPCodeFieldName
;
/** Parameter name for username. */
@Nonnull
@NotEmpty
private
String
usernameFieldName
;
/** Parameter name for password. */
@Nonnull
@NotEmpty
private
String
passwordFieldName
;
/** Parameter name for SSO bypass. */
@Nonnull
@NotEmpty
private
String
ssoBypassFieldName
;
/** Constructor. */
ExtractUsernamePasswordTOTPFromFormRequest
()
{
TOTPCodeFieldName
=
"TOTPCode"
;
usernameFieldName
=
"username"
;
passwordFieldName
=
"password"
;
ssoBypassFieldName
=
"donotcache"
;
}
// Handle input it should only be 6 digits
private
boolean
stringNotOnlyDigits
(
@Nonnull
@NotEmpty
final
String
TOTPCode
)
{
for
(
int
i
=
0
;
i
<
TOTPCode
.
length
();
i
++)
{
if
(!
Character
.
isDigit
(
TOTPCode
.
charAt
(
i
)))
{
return
true
;
}
}
return
false
;
}
/**
* Set the TOTPCode parameter name.
*
* @param fieldName the TOTPCode parameter name
*/
public
void
setTOTPCodeFieldName
(
@Nonnull
@NotEmpty
final
String
fieldName
)
{
ComponentSupport
.
ifInitializedThrowUnmodifiabledComponentException
(
this
);
TOTPCodeFieldName
=
Constraint
.
isNotNull
(
StringSupport
.
trimOrNull
(
fieldName
),
"TOTPCode field name cannot be null or empty."
);
}
/**
* Set the username parameter name.
*
* @param fieldName the username parameter name
*/
public
void
setUsernameFieldName
(
@Nonnull
@NotEmpty
final
String
fieldName
)
{
ComponentSupport
.
ifInitializedThrowUnmodifiabledComponentException
(
this
);
usernameFieldName
=
Constraint
.
isNotNull
(
StringSupport
.
trimOrNull
(
fieldName
),
"Username field name cannot be null or empty."
);
}
/**
* Set the password parameter name.
*
* @param fieldName the password parameter name
*/
public
void
setPasswordFieldName
(
@Nonnull
@NotEmpty
final
String
fieldName
)
{
ComponentSupport
.
ifInitializedThrowUnmodifiabledComponentException
(
this
);
passwordFieldName
=
Constraint
.
isNotNull
(
StringSupport
.
trimOrNull
(
fieldName
),
"Password field name cannot be null or empty."
);
}
/**
* Set the SSO bypass parameter name.
*
* @param fieldName the SSO bypass parameter name
*/
public
void
setSSOBypassFieldName
(
@Nonnull
@NotEmpty
final
String
fieldName
)
{
ComponentSupport
.
ifInitializedThrowUnmodifiabledComponentException
(
this
);
ssoBypassFieldName
=
Constraint
.
isNotNull
(
StringSupport
.
trimOrNull
(
fieldName
),
"SSO Bypass field name cannot be null or empty."
);
}
/** {@inheritDoc} */
@Override
protected
void
doExecute
(
@Nonnull
final
ProfileRequestContext
profileRequestContext
,
@Nonnull
final
AuthenticationContext
authenticationContext
)
{
final
UsernamePasswordTOTPContext
upCtx
=
authenticationContext
.
getSubcontext
(
UsernamePasswordTOTPContext
.
class
,
true
);
upCtx
.
setUsername
(
null
);
upCtx
.
setPassword
(
null
);
upCtx
.
setTOTPCode
(
null
);
upCtx
.
setIPAddress
(
null
);
final
HttpServletRequest
request
=
getHttpServletRequest
();
if
(
request
==
null
)
{
log
.
debug
(
"{} Profile action does not contain an HttpServletRequest"
,
getLogPrefix
());
ActionSupport
.
buildEvent
(
profileRequestContext
,
AuthnEventIds
.
NO_CREDENTIALS
);
return
;
}
final
String
username
=
request
.
getParameter
(
usernameFieldName
);
if
(
username
==
null
||
username
.
isEmpty
())
{
log
.
debug
(
"{} No username in request"
,
getLogPrefix
());
ActionSupport
.
buildEvent
(
profileRequestContext
,
AuthnEventIds
.
NO_CREDENTIALS
);
return
;
}
upCtx
.
setUsername
(
applyTransforms
(
username
));
final
String
password
=
request
.
getParameter
(
passwordFieldName
);
if
(
password
==
null
||
password
.
isEmpty
())
{
log
.
debug
(
"{} No password in request"
,
getLogPrefix
());
ActionSupport
.
buildEvent
(
profileRequestContext
,
AuthnEventIds
.
NO_CREDENTIALS
);
return
;
}
upCtx
.
setPassword
(
password
);
// Get TOTP code
final
String
TOTPCode
=
request
.
getParameter
(
TOTPCodeFieldName
);
if
(
TOTPCode
==
null
||
TOTPCode
.
isEmpty
()
||
TOTPCode
.
length
()
!=
6
||
stringNotOnlyDigits
(
TOTPCode
))
{
log
.
debug
(
"{} No valid TOTP code in request"
,
getLogPrefix
());
ActionSupport
.
buildEvent
(
profileRequestContext
,
AuthnEventIds
.
NO_CREDENTIALS
);
return
;
}
upCtx
.
setTOTPCode
(
TOTPCode
);
// Get client IP
final
String
IPAddress
=
request
.
getRemoteAddr
();
if
(
IPAddress
==
null
||
IPAddress
.
isEmpty
())
{
log
.
debug
(
"{} No IPAddress in request"
,
getLogPrefix
());
ActionSupport
.
buildEvent
(
profileRequestContext
,
AuthnEventIds
.
NO_CREDENTIALS
);
return
;
}
upCtx
.
setIPAddress
(
IPAddress
);
final
String
donotcache
=
request
.
getParameter
(
ssoBypassFieldName
);
if
(
donotcache
!=
null
&&
"1"
.
equals
(
donotcache
))
{
log
.
debug
(
"{} Recording do-not-cache instruction in authentication context"
,
getLogPrefix
());
authenticationContext
.
setResultCacheable
(
false
);
}
}
}
src/main/java/se/smhi/totp/PasscodeGenerator.java
0 → 100644
View file @
cfb18f02
package
se.smhi.totp
;
import
java.io.ByteArrayInputStream
;
import
java.io.DataInput
;
import
java.io.DataInputStream
;
import
java.io.IOException
;
import
java.nio.ByteBuffer
;
import
java.security.GeneralSecurityException
;
import
javax.crypto.Mac
;
/**
* An implementation of the HOTP generator specified by RFC 4226. Generates
* short passcodes that may be used in challenge-response protocols or as
* timeout passcodes that are only valid for a short period.
*
* The default passcode is a 6-digit decimal code and the default timeout
* period is 5 minutes.
*
* @author sweis@google.com (Steve Weis)
*
*/
public
class
PasscodeGenerator
{
/** Default decimal passcode length */
private
static
final
int
PASS_CODE_LENGTH
=
6
;
/** Default passcode timeout period (in seconds) */
private
static
final
int
INTERVAL
=
30
;
/** The number of previous and future intervals to check */
private
static
final
int
ADJACENT_INTERVALS
=
2
;
private
static
final
int
PIN_MODULO
=
(
int
)
Math
.
pow
(
10
,
PASS_CODE_LENGTH
);
private
final
Signer
signer
;
private
final
int
codeLength
;
private
final
int
intervalPeriod
;
/*
* Using an interface to allow us to inject different signature
* implementations.
*/
interface
Signer
{
byte
[]
sign
(
byte
[]
data
)
throws
GeneralSecurityException
;
}
/**
* @param mac A {@link Mac} used to generate passcodes
*/
public
PasscodeGenerator
(
Mac
mac
)
{
this
(
mac
,
PASS_CODE_LENGTH
,
INTERVAL
);
}
/**
* @param mac A {@link Mac} used to generate passcodes
* @param passCodeLength The length of the decimal passcode
* @param interval The interval that a passcode is valid for
*/
public
PasscodeGenerator
(
final
Mac
mac
,
int
passCodeLength
,
int
interval
)
{
this
(
new
Signer
()
{
public
byte
[]
sign
(
byte
[]
data
){
return