Comments (3)
@bdemers feel free to use the code, here is the complete working example handling the async stuff properly with completable futures, and polling properly.
#! /usr/bin/env groovy
import com.okta.authn.sdk.AuthenticationStateHandler
import com.okta.authn.sdk.client.AuthenticationClient
import com.okta.authn.sdk.client.AuthenticationClients
import com.okta.authn.sdk.AuthenticationStateHandlerAdapter
import com.okta.authn.sdk.impl.resource.DefaultVerifyPassCodeFactorRequest
import com.okta.authn.sdk.resource.AuthenticationResponse
import com.okta.authn.sdk.resource.Factor
import com.okta.authn.sdk.resource.VerifyFactorRequest
import groovy.transform.Field
import java.util.concurrent.CompletableFuture
import java.util.concurrent.Future
@Grapes([
@Grab(group='com.okta.authn.sdk', module='okta-authn-sdk-api', version='0.1.0'),
@Grab(group='com.okta.authn.sdk', module='okta-authn-sdk-impl', version='0.1.0'),
@Grab(group='com.okta.sdk', module='okta-sdk-httpclient', version='1.2.0')
// @Grab(group='ch.qos.logback', module='logback-classic', version='1.2.3')
])
@Field
def oktaUrl = System.getenv('OKTA_URL')
@Field
def oktaApiKey = System.getenv('OKTA_API_KEY')
@Field
def oktaUserName = System.getenv('OKTA_USERNAME')
@Field
String oktaPassword = System.getenv('OKTA_PASSWORD')
def main() {
// Set the api token for the okta client to use, why can't I pass it into the client, wtf?
System.setProperty("okta.client.token", oktaApiKey)
AuthenticationClient client = AuthenticationClients.builder()
.setOrgUrl(oktaUrl)
.build()
String username = oktaUserName ? oktaUserName : System.console().readLine('What is your Okta username? ')
char[] passwordCharArr
if (!oktaPassword) {
print "What is your Okta password? "
passwordCharArr = System.console().readPassword()
} else {
passwordCharArr = oktaPassword.toCharArray()
}
CompletableFuture<AuthenticationResponse> authenticationResponseCompletableFuture = new CompletableFuture<>()
AuthenticationStateHandler stateHandler = new MyAuthenticationStateHandler(client, authenticationResponseCompletableFuture)
client.authenticate(username, passwordCharArr, null, stateHandler)
AuthenticationResponse authResponse = authenticationResponseCompletableFuture.get()
println("Final auth status:: ${authResponse.getStatus()}")
}
class MyAuthenticationStateHandler extends AuthenticationStateHandlerAdapter {
AuthenticationClient client
CompletableFuture<AuthenticationResponse> authenticationResponseFuture;
MyAuthenticationStateHandler(AuthenticationClient client, Future<AuthenticationResponse> authenticationResponseFuture) {
this.client = client
this.authenticationResponseFuture = authenticationResponseFuture
}
void handleMfaChallenge(AuthenticationResponse mfaChallengeResponse) {
if (! (mfaChallengeResponse.getFactors().get(0).get("factorType") == "push")) {
return
}
println "waiting for factor to be verified"
sleep(1000)
VerifyFactorRequest request = client.instantiate(VerifyFactorRequest.class)
request.setStateToken(mfaChallengeResponse.getStateToken())
def id = mfaChallengeResponse.getFactors().get(0).getId()
if (mfaChallengeResponse.getFactorResult() == "REJECTED") {
println "user failed to authenticate"
authenticationResponseFuture.complete(mfaChallengeResponse)
return
}
client.verifyFactor(id, request, this)
}
@Override
void handleSuccess(AuthenticationResponse successResponse) {
println "successfully approved"
authenticationResponseFuture.complete(successResponse)
}
@Override
void handleUnauthenticated(AuthenticationResponse unauthenticatedResponse) {
println "user failed to authenticate"
authenticationResponseFuture.complete(unauthenticatedResponse)
}
void handleMfaRequired(AuthenticationResponse mfaRequiredResponse) {
println "MFA is require found the following factors:"
mfaRequiredResponse.getFactors().eachWithIndex { Factor factor, int i ->
println "${i}: ${factor.getProvider()} ${factor.getType()}"
}
def factorSelection = Integer.valueOf(System.console().readLine('Select factor to verify? '))
def factor = mfaRequiredResponse.getFactors().get(factorSelection)
def type = factor.getType().toString()
switch (type) {
case "token:software:totp":
handleCode(factor, mfaRequiredResponse.getStateToken())
break
case "sms":
triggerCodeGeneratingFactorAndPromptForCode(factor, mfaRequiredResponse.getStateToken())
break
case "call":
triggerCodeGeneratingFactorAndPromptForCode(factor, mfaRequiredResponse.getStateToken())
break
case "push":
handlePush(factor, mfaRequiredResponse.getStateToken())
break
default:
throw new RuntimeException("Unknown factor type: ${type}")
}
}
void handleUnknown(AuthenticationResponse typedUnknownResponse) {
println("unknown / unhandled status: ${typedUnknownResponse.getStatus()} res: ${typedUnknownResponse}")
authenticationResponseFuture.complete(typedUnknownResponse)
}
def triggerCodeGeneratingFactorAndPromptForCode(Factor factor, String stateToken) {
client.challengeFactor(factor.getId(), stateToken, this)
def code = System.console().readLine('Enter code: ')
verifyCode(code, factor.getId(), stateToken)
}
def handleCode(Factor factor, String stateToken) {
def otp = System.console().readLine('Enter one time code: ')
verifyCode(otp, factor.getId(), stateToken)
}
def handlePush(Factor factor, String stateToken) {
println("Triggering challenge")
client.challengeFactor(factor.getId(), stateToken, this)
}
def verifyCode(String code, id, stateToken) {
DefaultVerifyPassCodeFactorRequest request = client.instantiate(DefaultVerifyPassCodeFactorRequest.class)
request.setPassCode(code)
request.setStateToken(stateToken)
client.verifyFactor(id, request, this)
}
}
main()
from okta-auth-java.
Hey @fieldju !
First off, this is a great example! Any objection on my porting this to Java and including it as one of our examples?
Next, this is defiantly a bug. It looks like we poll for the factor activation in pollFactor
instead of the transaction. We will likely add a pollForFactorActivation
and pollForFactorVerification
(or something slightly better named)
from okta-auth-java.
@fieldju I haven't forgot about you! I'm just trying to wrap up another task before jumping into this.
I did have a little bit of time to play with this, and it isn't as bad as i thought (I think i need to renamed the current polling method). In the short term, you can use the challengeFactor
to check the state of the factor. IIRC client.challengeFactor(factor.getId(), resp.getStateToken(), this)
should do it. It ultimately calls the correct endpoint.
(but the naming is not clear, so we will fix that)
Also can I get you to sign our CLA, for the contribution of the CLI example? I think this is a much easier to show basic usage of this API 💯!
Thanks again!
from okta-auth-java.
Related Issues (20)
- Unable to use "correctAnswer" from AuthenticationResponse. HOT 17
- unable to find API to send MFA Enroll activation link via email/sms HOT 3
- Error while updating Plaid SDK 3.5.0 (Duplicate class org.bouncycastle.LICENSE) HOT 3
- Missing nullability annotations in AuthenticationStateHandler HOT 3
- is:issue is:open Okta authentication crashes, maybe okhttp library compatibility. HOT 4
- HttpClientConfiguration.getRequestExecutorParams() deprecated
- AuthenticationException localizedMessages do not adhere to Android device locale settings HOT 1
- authenticationClient.authenticate() does not return locked_out status HOT 1
- 2.0.5 dependencies result in build error HOT 2
- Resend OTP after 5 minutes - MFA. HOT 4
- enrollFactor method HOT 12
- DefaultAuthenticationClient.translateException() should be able to handle null errorCode HOT 2
- Failed resolution of: Ljava/time/format/DateTimeFormatter on Android 7 devices HOT 6
- Getting NoClassDefFound for BaseClient.java while using okta-authn-sdk-api:2.0.9 with okta-sdk-api:10.0.0 HOT 4
- Upgrade dependency okta-sdk-java version HOT 7
- Security vulnerability via transitive `dependencybcprov-jdk18on:1.75` HOT 3
- forgot password with trusted application HOT 9
- Primary authentication with trusted application not supported by SDK HOT 4
- Authentication Client Verify Factor throws Resource Exception instead of AuthenticationException HOT 4
- Incorrect key while retrieving correct answer from EmbeddedResponse HOT 1
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from okta-auth-java.