Git Product home page Git Product logo

okta-idx-java's People

Contributors

arvindkrishnakumar-okta avatar bdemers avatar bjr-okta avatar bretterer avatar chrisdmills-okta avatar codepadma avatar jaynewstrom avatar karthikaselvaraj-okta avatar kostiantyndrozd-okta avatar prejayak avatar sergiishamrai-okta avatar vijetmahabaleshwar-okta avatar vitaliitytarenko-okta avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

okta-idx-java's Issues

Allow setting `DeviceContext` per interaction

For a web application that is using a single instance of IDXAuthenticationWrapper the DeviceContext will be different for each client (different IP X-Forwarded-For and User-Agent)

This context information would need to be known at the start of a new IDX transaction, e.g. something like:

idxAuthenticationWrapper.begin(deviceContext)

Without this, Okta Verify and email factors do NOT show the user's location/user agent.

Log spam in `com.okta.idx.sdk.api.client.WrapperUtil`

These should be at least debug. This would create a lot of log space, since every user auth request would print out a log message similar to:

14:33:30.240 [main] INFO  c.o.idx.sdk.api.client.WrapperUtil - Remediation options: [identify]

static void printRemediationOptions(IDXResponse idxResponse) {
if (idxResponse != null && idxResponse.remediation() != null) {
RemediationOption[] remediationOptions = idxResponse.remediation().remediationOptions();
logger.info("Remediation options: {}", Arrays.stream(remediationOptions)
.map(RemediationOption::getName)
.collect(Collectors.toList()));
} else {
logger.info("Remediation options unavailable");
}
}

`fetchSignUpFormValues()` throws NullPointerException

Trying to go with the registration flow but getting the following

Exception in thread "main" java.lang.NullPointerException: Cannot invoke "String.length()" because "this.input" is null
	at java.base/java.net.URI$Parser.parse(URI.java:3164)
	at java.base/java.net.URI.<init>(URI.java:623)
	at java.base/java.net.URI.create(URI.java:904)
	at com.okta.commons.http.DefaultRequest.<init>(DefaultRequest.java:59)
	at com.okta.idx.sdk.api.client.BaseIDXClient.enroll(BaseIDXClient.java:257)
	at com.okta.idx.sdk.api.client.IDXAuthenticationWrapper.lambda$fetchSignUpFormValues$21(IDXAuthenticationWrapper.java:704)
	at com.okta.idx.sdk.api.client.AuthenticationTransaction.proceed(AuthenticationTransaction.java:101)
	at com.okta.idx.sdk.api.client.IDXAuthenticationWrapper.fetchSignUpFormValues(IDXAuthenticationWrapper.java:700)

Used to work just fine, but after switching the secret for OIDC web application in my tenant I see the above exception. Interaction code flow enabled for the app, allowed in the access policy too.

When running registration from browser js-idx through other application (PKCE SPA), all works fine.

Please advise!

Verifying an Okta Verify Challenge using TOTP using `VerifyAuthenticatorOptions` sets wrong value

Calling IDXAuthetnicationWrapper.verifyAuthenticator(ProceedContext proceedContext, VerifyAuthenticatorOptions verifyAuthenticatorOptions) always sets the credential passcode.

This doesn't match the patterns use else were in the SDK where the current transaction context is used to set the correct value.

For example in the case of credentials.setTotp() should be called instead.

Current work around is to use: IdxAuthenticationWrapper.verifyAuthenticator(proceedContext, new VerifyChannelDataOptions("totp", code)); instead.
But the caller doesn't have any context available in the AuthenticationResponse to know if this is a totp code or not.
(and requires a magic string

`IDXAuthenticationWrapper.authenticate()` should take refresh token as input

I need to do biometric login with a refresh token, as per your docs the following endpoint and response should be part of your IDX SDK:

POST /oauth2/default/v1/token HTTP/1.1
Accept: application/json
Content-Type: application/x-www-form-urlencoded

grant_type=refresh_token
redirect_uri=com.embeddedauth://callback
scope=offline_access openid profile
refresh_token=03_hBtVj-Hk0Mxo9TPSdl7TLkxQioKqQEzud3ldqHqs
client_id=0oa94el1z4nUDxx0z5d7

Response

{
    "token_type": "Bearer",
    "expires_in": 3600,
    "access_token": "eyJraWQiOiJoQkZNR...",
    "scope": "offline_access openid profile",
    "refresh_token": "HRzOBfj1A1g6akWqNHfCE-KX-9NASmnFqhRFOt_rEdc", // refresh_token can change
    "id_token": "eyJraWQiOiJoQkZN..."
}

But it seems like authenticate() in your SDK only supports password based authentication, not token based.

AuthenticatorEnrollments.getValue() should be a Collection instead of an array

To match other parts of the IDX SDK, this object should be a list (or other collection) type.

This would be a breaking change, but another method could be introduced into AuthenticatorEnrollments to keep it backward compatible.

For example, the object could implement iterable and have a stream() method.

Something like:

Stream<AuthenticatorEnrollment> stream() {
    if (value == null) {
        return Stream.empty();
    }
    return Arrays.stream(getValue());
}

@Override
public Iterator<AuthenticatorEnrollment> iterator() {
    return stream().iterator();
}

Could not find artifact com.okta.idx.sdk:okta-idx-java-api:jar:3.0.7-SNAPSHOT

[ERROR] Failed to execute goal on project okta-idx-java-embedded-sign-in-widget: Could not resolve dependencies for
project com.okta.idx.sdk:okta-idx-java-embedded-sign-in-widget:jar:3.0.7-SNAPSHOT: The following artifacts could not be
resolved: com.okta.idx.sdk:okta-idx-java-api:jar:3.0.7-SNAPSHOT (absent): Could not find artifact com.okta.idx.sdk:okta
idx-java-api:jar:3.0.7-SNAPSHOT in sonatype-nexus-snapshots (https://oss.sonatype.org/content/repositories/snapshots)

It appears this artifact isn't in the repo:
image

For now I just changed the pom.xml to reference 3.0.6.

Unexpected end of stream error

Hi, We are using Okta IDX SDK (version: 3.0.4) for auth and MFA in our android app. In both production & QA, we see the following particular error happening quite often:
com.okta.commons.http.HttpException: unexpected end of stream on https://qa.login.***.com. It’s thrown from Okta SDK functions.
This error has been thrown from Okta SDK functions, mostly when calling SDK to send challenge code to a selected factor (after userid/pass verified), secondly when calling SDK to verify the entered OTP. The SDK login call with userId/pass also recorded such error (less frequent than the other two).
Once getting such error, retrying the operation again seems to help. Close and reopen the app seems can help.

Please find the details and STR for one of the scenarios below:
Steps to reproduce:
Log in with username/password .
After successful idxAuthenticationWrapper.verifyAuthenticator(
authResponse.proceedContext,
VerifyAuthenticatorOptions(password)
) call, which returns two options email and mobile.
Click on either options really quick and this calls select Authenticator IDXAuthenticationWrapper.selectAuthenticator(ProceedContext proceedContext,com.okta.idx.sdk.api.client.Authenticator authenticator).

Issue:
Getting the below exception
com.okta.commons.http.HttpException: unexpected end of stream on https://qa.login.***.com/..

Please advise if it’s a known issue. Any help/ directions to fix this issue is appreciated.

Thank you!

When enrolling an Okta Verify Factor the `pollInfo` is `null`

I have an org and application set up to require both a password and Okta Verify (with factor enrollment setup)

IDXAuthenticationWrapper idxAuthenticationWrapper = new IDXAuthenticationWrapper();

AuthenticationResponse authenticationResponse = idxAuthenticationWrapper.begin();

ProceedContext proceedContext = authenticationResponse.getProceedContext();

AuthenticationOptions authenticationOptions = new AuthenticationOptions(username, password);

authenticationResponse = idxAuthenticationWrapper.authenticate(authenticationOptions, proceedContext);

This last authenticationResponse is in the AWAITING_POLL_ENROLLMENT state.

I'm expecting the authenticationResponse.getProceedContext().getPollInfo().getRefresh() to contain a value (related see #315)
however getPollInfo() returns null.

NOTE: there proceedContext.refresh IS set to "4000" (looks like a similar issue to #315). But this does NOT match to get the polling information used in other places. i.e. when verifying an email factor.

HTTP debugging

I noticed that a different transport library is being used in this project, which does not allow having inspection of HTTP req/resp.

Are there any plans to make it available?

RemediationOption.getRefresh() should return a Duration

Similar to: #315
RemediationOption.refresh should match the pattern used in PollInfo.refresh

It's currently a string which requires a user to do something like:

Integer.parseInt(authenticationResponse.getCurrentAuthenticatorEnrollment().getValue().getPoll().getRefresh())

Add password requirement settings entity to `CurrentAuthenticatorEnrollmentValue`

Hi, can you please extend CurrentAuthenticatorEnrollmentValue(or AuthenticatorEnrollment) class with "settings" entity, which contain pasword requirements details. I see this infomation in response(look bellow) of selectAuthenticator() call, but this data is missed just because of class definition which doesn't contain corresponding entity. Password requirements is useful for dinamic registration form buidling based on fetchSignUpFormValues() and authenticators details. And for example Sign-In-Widget use this data. Thank you in advance.

Response example:

"currentAuthenticator": {
        "type": "object",
        "value": {
            "type": "password",
            "key": "okta_password",
            "id": "aut4okoutugDsoHpI5d7",
            "displayName": "Password",
            "methods": [{
                    "type": "password"
                }
            ],
            "settings": {
                "complexity": {
                    "minLength": 8,
                    "minLowerCase": 1,
                    "minUpperCase": 1,
                    "minNumber": 0,
                    "minSymbol": 0,
                    "excludeUsername": true,
                    "excludeAttributes": []
                },
                "age": {
                    "minAgeMinutes": 0,
                    "historyCount": 4
                }
            }
        }
    },

Class definition:

public class CurrentAuthenticatorEnrollmentValue {
    private Recover recover;
    private String type;
    private String id;
    private String key;
    private String displayName;
    private RemediationOption resend;
    private RemediationOption poll;
    private ContextualData contextualData;
    private Profile profile;

Making a request to `IDXAuthenticationWrapper.begin()` when Authorization Server is not configured for `Interaction Code` hides error

If the Authorization Server is not configured correctly (with "Interaction Code" enabled), the error message is not available in the response objects.

If you turn on wire logging you can see the error message was available in the actual response:

{
   "version":"1.0.0",
   "stateHandle":"<a-state-token>",
   "expiresAt":"2021-06-24T16:42:21.000Z",
   "intent":"LOGIN",
   "messages":{
      "type":"array",
      "value":[
         {
            "message":"You are not allowed to access this app. To request access, contact an admin.",
            "i18n":{
               "key":"idx.error.code.no_matching_policy"
            },
            "class":"ERROR"
         }
      ]
   },
   "failure":{
      "name":"failure-redirect",
      "href":"https://oie-123456.oktapreview.com/login/error/redirect?stateToken=<my-state-token>"
   }
}

Enroll OktaVerify with SMS channel name does not match expected value

The IDXAuthenticationWrapper verifyAuthenticator() does not support the sms channel name, It assumes the channel name is phoneNumber instead.

if("phoneNumber".equals(verifyChannelDataOptions.getChannelName())) {
builder.withPhoneNumber(verifyChannelDataOptions.getValue());

I'm not sure there are places where the channelName might be phoneNumber if so, the above block should look something like:

if("phoneNumber".equals(verifyChannelDataOptions.getChannelName())
    || "sms".equals(verifyChannelDataOptions.getChannelName()) {

NPE when AuthenticationOptions.password is null

There are few calls to in AuthenticationOptions that assume the password field is not null, these throw NPEs:

credentials.setPasscode(authenticationOptions.getPassword().toCharArray());

This may prevent passwordless flows from working correctly.

Passwords should not be represented as a String inside of the SDK as well:
https://www.geeksforgeeks.org/use-char-array-string-storing-passwords-java/

Unable to find a 'com.okta.commons.http.RequestExecutorFactory' implementation on the classpath

Error initializing IDXAuthenticationWrapper

IDXAuthenticationWrapper idxWrapper = new IDXAuthenticationWrapper(issuer, clientId, clientSecret, scopes, redirectUri);

AuthenticationResponse beginResponse = idxWrapper.begin();

ProceedContext beginProceedContext = beginResponse.getProceedContext();
AuthenticationResponse newUserRegistrationResponse = idxWrapper.fetchSignUpFormValues(beginProceedContext);

Encountering the error after adding okta-http-api-1.3.5, okta-http-okhttp-1.3.5, okta-sdk-httpclient-8.2.5 etc.

Could someone please help to resolve this issue?

Replace remove the need for calling `getValue()` methods on model objects

It looks like the API leaks the .value JSON element into the API, which means the developer needs to call .getValue() in a few different places.

Ideally this should be handled when the JSON is parsed, so a developer can call something like:

userProfileFormValue.form()

instead of:

userProfileFormValue.form().getValue();

Establish a Confidential Client

    @PostMapping(path = "/verify", produces = {
                    MediaType.APPLICATION_JSON_VALUE })
    public ResponseEntity<Registration> verify(@RequestParam(name = "token") String activationToken,
                    @RequestBody(required = false) Registration registration, final HttpServletRequest request,
                    final HttpSession session) {

            final RequestContext requestContext = OktaUtils.constructRequestContext();
            requestContext.setUserAgent(request.getHeader("USER-AGENT"));
            requestContext.setIpAddress(request.getRemoteAddr());

            AuthenticationResponse beginResponse = idxAuthenticationWrapper.beginUserActivation(activationToken,
                            requestContext);

            log.info("Begin Response Status {}",
                            beginResponse.getAuthenticationStatus());

             return new ResponseEntity<>(HttpStatus.OK);

}

Okta returns error: Error Detail: [invalid_request:Only confidential clients can use the activation token flow]

Question: How do you establish a confidential client

Unexpected end of stream error

Hi,
We are using Okta IDX SDK (version: 3.0.6) for auth and MFA in our android app. We see the following particular error happening quite often again: com.okta.commons.http.HttpException: unexpected end of stream on https://qa.login.***.com. It’s thrown from Okta SDK functions.
This error has been thrown from Okta SDK functions, mostly when calling SDK to send challenge code to a selected factor (after userid/pass verified), secondly when calling SDK to verify the entered OTP. The SDK login call with userId/password also recorded such error (less frequent than the other two).
Once getting such error, retrying the operation again seems to help. Close and reopen the app seems can help.
Please find the details and STR for one of the scenarios below:
Steps to reproduce:
Log in with username/password .
After successful idxAuthenticationWrapper.verifyAuthenticator(
authResponse.proceedContext,
VerifyAuthenticatorOptions(password)
) call, which returns two options email and mobile.
Click on either options really quick and this calls select Authenticator IDXAuthenticationWrapper.selectAuthenticator(ProceedContext proceedContext,com.okta.idx.sdk.api.client.Authenticator authenticator).
Issue:
Getting the below exception
com.okta.commons.http.HttpException: unexpected end of stream on https://qa.login.***.com/..
Please advise if it’s a known issue. Any help/ directions to fix this issue is appreciated
We upgraded to 3.0.6(on June 22nd) and it helped sometime (around 3weeks) we did not see any errors until July 6th, and these errors are back again.

Please refer to #445 we raised for same issue before.

Appreciate you help for resolving this issue.

Error logged on successful request [Log spam]

At the end of a successful authentication flow using (email, okta verify, etc) there are errors in the log:

ERROR com.okta.idx.sdk.api.client.AuthenticationTransaction - ProceedContext is null
INFO com.okta.idx.sdk.api.client.AuthenticationTransaction - Login Successful!

It looks like there are some valid cases where the ProceedContext is null (possible in the SUCCESS state, since that is the end of the flow?), this should NOT log an error. This is log spam and may result in lots of confusing log lines for usages with a high volume of authentications

getting null pointer exception when we give the wrong OTP for more than 5 times

While verifying the email/phone OTP, when we give wrong OTP for more than 5 times, we are getting null pointer exception.

I observed that in BaseIDXClient.java Line 597 we are getting this error.

Current code is : response.getHeaders().getContentType() != null && response.getHeaders().getContentType().toString().contains("application/json") || response.getHeaders().getContentType().toString().contains("application/ion+json")

Actual code should be: response.getHeaders().getContentType() != null && (response.getHeaders().getContentType().toString().contains("application/json") || response.getHeaders().getContentType().toString().contains("application/ion+json"))

Also is it possible to get meaningful messages when we get 429 error from the APIs when we are trying to verify the OTP?
Currently, we are getting this error: Request to https://xxxxx/idp/idx/challenge/answer failed. HTTP status: 429
Previously we were getting a different message like Max tries reached.

OptionalPropertySource swallows/hides exceptions

This looks like it was a problem in the management SDK as well:

The original exception is lost, so when you have malformed YAML it's difficult to track down. The "property source" object's toString() isn't descriptive enough (see comment in block below)

Depending on how you want to manage this, you could either just log the exception in debug or you could add the original message, and log the exception only on trace.

    @Override
    public Map<String,String> getProperties() {
        try {
            return propertiesSource.getProperties();
        } catch (Exception | NoClassDefFoundError e) {

            // this log message, logs with a class hash, which isn't helpful to figure out what is wrong:
            // Unable to obtain properties from optional properties source com.okta.idx.sdk.api.config.ResourcePropertiesSource@460d0a57: source
            if (log.isTraceEnabled()) {
                log.trace("Unable to obtain properties from optional properties source {}", propertiesSource, e);
            } else {
                log.debug("Unable to obtain properties from optional properties source {}: {}", propertiesSource, e.getMessage());
            }
        }
        return new LinkedHashMap<>();
    }

User-Agent is hard coded

See:

private static final String USER_AGENT_HEADER_VALUE = "okta-idx-java/2.0.0";

The version should get picked up automatically if you include an META-INF/okta/version.properties file

For example:
https://github.com/okta/okta-jwt-verifier-java/blob/c3e44c142472fe34e6eaac1443b9a75f7c2e7368/impl/src/main/resources/META-INF/okta/version.properties

And enabler version filtering in the pom:
https://github.com/okta/okta-jwt-verifier-java/blob/c3e44c1/impl/pom.xml#L123-L129

The current user's information is not available in the `AuthenticationResponse`

User information (email address) is returned from Okta (along with other user attributes, like timezone, etc)

Info returned from Okta:

  "user" : {
    "type" : "object",
    "value" : {
      "id" : "<id>",
      "identifier" : "<username/email>",
      "profile" : {
        "firstName" : "<First Name>",
        "lastName" : "<Last Name>",
        "timeZone" : "America/Los_Angeles",
        "locale" : "en_US"
      }
    }
  },

This information should be returned to the caller, the identifier could be used as a default value when collecting the email address used when enrolling an email factor

OK HTTP Client connection pool thread hangs

I created a simple application:

public class Application {

    public static void main(String[] args) {

            IDXAuthenticationWrapper idxWrapper = new IDXAuthenticationWrapper();
            AuthenticationResponse response = idxWrapper.begin();
    }
}

The main method exits right exits as expected, but the JVM does not consistently stop due to something in OK HTTP. Switching to HTTP client resolves this problem.

Possibly we need to add a listener to the JVM to clean up the thread pool (or whatever thread is active)

When enrolling in an Authenticator with multiple factors `AWAITING_CHANNEL_DATA_ENROLLMENT` doesn't not contain context

When enrolling an Okta Verify Authenticator, there are multiple factor options for enrollment.
From the AWAITING_AUTHENTICATOR_ENROLLMENT_SELECTION state the client would make a call similar to:

AuthenticationResponse response = idxAuthenticationWrapper.selectFactor(proceedContext, selectedFactor);
// for example the `selectedFactor` is an email factor instance

This puts the client into the AWAITING_CHANNEL_DATA_ENROLLMENT state. The response from Okta returns enough context that the client should know what is going on, however, this context is NOT added to the AuthenticationResponse returned from the IdxAuthenticationWrapper.

The current workaround is to add the previously selected factor into some sort of state management (like an HTTP Session).

The ContextualData (or something similar) should contain the type of information needed to continue the flow.

recoverPassword() method not returning authenticator enrollment list

Trying to implement password recovery flow using idx sdk but having issue with not getting back list of authenticator in response for recoverPassword method
As per the below documentation, the response should come back with authenticatorStatus and authenticators. Getting the authenticatorStatus but not the list of authenticators
https://developer.okta.com/docs/guides/oie-embedded-sdk-use-case-pwd-recovery-mfa/java/main/#summary-of-steps
Steps to reproduce:

  1. Create user with basic attributes (login,email,fname,lname) and password
  2. Email authenticator is set for Recovery and selected in password policy as well
  3. App sign-on policy has only password as factor
  4. Start authenticate flow by passing username
  5. call recoverPassword by passing username and proceed context
  6. In response authenticatorStatus = AWAITING_AUTHENTICATOR_SELECTION but not seeing the list of authenticators
    image

Creating user should have a more intuitive API

To sign up a user via SSR, a call to fetchSignUpFormValues happens, and then the developer must implement something like:

Optional<FormValue> userProfileFormValue = newUserRegistrationResponse.getFormValues()
                    .stream()
                    .filter(x -> x.getName().equals("userProfile"))
                    .findFirst();

If this is always the top level object, for SSR, add a method of getUserProfile() or allow the developer to call setUserProfile(Map<String, String>)

or possibly add typed methods for the common user profile attributes. For example, out of the box firstName, lastName, and email are required.

PollInfo.getRefresh() should be a number

Likely an integer, but this could also be Duration, currently it is NOT clear what the unit is (I'm assuming is millis), using a Duration could resolve any confusion.

Currently it is a String which requires the user to parse the value

Add support for UserInfo Endpoint

The current embedded auth sample requires the user to configure the issuer twice, and create an additional HTTP client (which may have different timeouts/proxy settings, etc)

Direct support should be added to this client.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo 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.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.