rburgst/okhttp-digest

Dynamically Change Credentials

Closed this issue · 3 comments

Hello everyone.
I need to change the Credentials on runtime without having to build a new instance of my OkHttpClient.
Is it possible? What would be a good alternative?

I am using Dagger2 to keep singleton instances of my Retrofit and OkHttpClient. It works flawlessly with the credentials of the 'default' user but I need to change them later on to access other methods.

    @Provides
    @Singleton
    @DigestAuth
    Credentials provideDigestAuthCredentials(){
        return new Credentials("default", "default");
    }

    @Provides
    @Singleton
    @DigestAuth
    OkHttpClient provideDigestAuthOkHttpClient(@DigestAuth Credentials credentials,
                                               @DigestAuth UrlHostSelectionInterceptor urlHostSelectionInterceptor){
        final DigestAuthenticator digestAuthenticator = new DigestAuthenticator(credentials);
        final Map<String, CachingAuthenticator> authCache = new ConcurrentHashMap<>();
        return new OkHttpClient.Builder()
                .addInterceptor(urlHostSelectionInterceptor)
                .authenticator(new CachingAuthenticatorDecorator(digestAuthenticator,authCache))
                .addInterceptor(new AuthenticationCacheInterceptor(authCache))
                .build();
    }

    @Provides
    @Singleton
    @DigestAuth
    Retrofit provideDigestAuthRetrofit(@DigestAuth OkHttpClient okHttpClient, Gson gson){
        return new Retrofit.Builder()
                .baseUrl(GlobalConstants.LAN_DEFAULT_URL)
                .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
                .addConverterFactory(GsonConverterFactory.create(gson))
                .client(okHttpClient)
                .build();
    }

Hello!
I have been using thus far something like this, since I don't have the credentials on app startup:

public interface CredentialsProvider {
    @Nullable String getIdentity();
    @Nullable String getPassword();
}

public class Credentials extends com.burgstaller.okhttp.digest.Credentials {
    private final @NonNull CredentialsProvider provider;

    public Credentials(
            @NonNull CredentialsProvider provider
    ) {
        super(null, null);
        this.provider = Check.nonNull(provider);
    }

    @Override
    public @Nullable String getUserName() {
        return provider.getIdentity();
    }

    @Override
    public @Nullable String getPassword() {
        return provider.getPassword();
    }

    @Override
    public final void setUserName(String userName) {
        throw new UnsupportedOperationException();
    }

    @Override
    public final void setPassword(String password) {
        throw new UnsupportedOperationException();
    }
}

By using an interface to supply the credentials you can avoid recreating the whole client, but maybe the cache Map<String, CachingAuthenticator> should be cleared when changing them.

clearing the cache is definitely necessary as pre-existing authentications will probalby no longer work.

sorry for not coming back earlier

I have added a test case for how updating the username/password mid-flight. https://github.com/rburgst/okhttp-digest/blob/master/src/test/java/com/burgstaller/okhttp/basic/BasicAuthenticatorWithMockWebserverTest.java#L111.
Please let me know if I should keep this issue open, otherwise I will close it in the coming days.