Role based in memory authentication without password in Spring Boot Security - spring-security

I am trying to authorize URLs to users with authority like ADMIN/LEAD/AGENT.
UsernamePasswordAuthenticationToken takes two arguments but I would like to pass 3 args userid , password as null and role of userid.
I have application-users.txt
{
"users": ["userid1","userid2","userid3","userid4"],
"agents": ["userid1"],
"leads": ["userid2"],
"admins": ["userid4"]
}
#Configuration
#EnableGlobalMethodSecurity(securedEnabled = true)
#EnableWebSecurity
#ConditionalOnWebApplication
#ConfigurationPropertiesScan("com.spectrum.sci.config")
#EnableConfigurationProperties(ApplicationClients.class)
#RequiredArgsConstructor
public class SecurityConfiguration extends WebSecurityConfigurerAdapter{
private static final Logger log = LoggerFactory.getLogger(SecurityConfiguration.class);
#Autowired
OrderDetailsUsers orderDetailsUsers;
public void configure(HttpSecurity httpSecurity) throws Exception {
httpSecurity
.authorizeRequests()
.antMatchers("/order/greet").hasAnyAuthority("admins","leads")
.antMatchers("/order").hasRole("agents")
.anyRequest()
.authenticated()
.and()
.httpBasic();
}
#Bean
public InMemoryUserDetailsManager inMemoryUserDetailsManager() {
final InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();
log.info("Importing {} clients: " , applicationClients.getClients().toString());
AuthenticationManager authenticationManager = null;
KeyValues kvAgents = orderDetailsUsers.applicatonUsers.getAgents();
String keyAgent = kvAgents.getKey();
String[] valueAgents = kvAgents.getValues();
for (int i = 0; i < valueAgents.length ; i++) {
Authentication authentication =
new UsernamePasswordAuthenticationToken(keyAgent, null, valueAgents[i]);
SecurityContextHolder.getContext().setAuthentication(authentication);
authenticationManager.authenticate(authentication);
manager.setAuthenticationManager(authenticationManager);
}
return manager;
}
}
#Component
public class OrderDetailsUsers {
private static final Logger log = LoggerFactory.getLogger(OrderDetailsUsers.class);
private ResourceLoader resourceLoader;
//#Autowired
ApplicationUsers applicatonUsers = new ApplicationUsers();
public OrderDetailsUsers(ResourceLoader resourceLoader) {
this.resourceLoader = resourceLoader;
}
#PostConstruct
public void init() {
try {
log.info("Trying to load users...");
Resource resource = resourceLoader.getResource("classpath:application-users.txt");
InputStream inputStream = resource.getInputStream();
log.info("inputStream = " + inputStream.toString());
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream, "UTF-8"));
StringBuilder stringBuilder = new StringBuilder();
String str;
while ( (str = bufferedReader.readLine()) != null) {
stringBuilder.append(str);
}
log.info("stringBuilder = " + stringBuilder.toString());
JsonObject jsonObject = new JsonParser().parse(stringBuilder.toString()).getAsJsonObject();
JsonArray users = jsonObject.get("users").getAsJsonArray();
log.info("users = " + users.toString());
String[] strUsersArray = toStringArray(users);
KeyValues kvUsers = new KeyValues();
kvUsers.setKey("users");
kvUsers.setValues(strUsersArray);
applicatonUsers.setUsers(kvUsers);
log.info("final users = " + applicatonUsers.getUsers().toString());
JsonArray agents = jsonObject.get("agents").getAsJsonArray();
log.info("agents = " + agents.toString());
String[] strAgentsArray = toStringArray(agents);
KeyValues kvAgents = new KeyValues();
kvAgents.setKey("agents");
kvAgents.setValues(strAgentsArray);
applicatonUsers.setAgents(kvAgents);
log.info("final Agents = " + applicatonUsers.getAgents().toString());
JsonArray leads = jsonObject.get("leads").getAsJsonArray();
log.info("leads = " + leads.toString());
String[] strLeadsArray = toStringArray(leads);
KeyValues kvLeads = new KeyValues();
kvLeads.setKey("leads");
kvLeads.setValues(strLeadsArray);
applicatonUsers.setLeads(kvLeads);
log.info("final leads = " + applicatonUsers.getLeads().toString());
JsonArray admins = jsonObject.get("admins").getAsJsonArray();
log.info("admins = " + admins.toString());
String[] strAdminsArray = toStringArray(admins);
KeyValues kvAdmins = new KeyValues();
kvAdmins.setKey("admins");
kvAdmins.setValues(strAdminsArray);
applicatonUsers.setAdmins(kvAdmins);
log.info("final admins = " + applicatonUsers.getAdmins().toString());
} catch(IOException | NullPointerException e) {
log.error("Failing to load users..." , e);
}
}
public static String[] toStringArray(JsonArray jsonArray) {
if (jsonArray == null)
return null;
String[] strArray = new String[jsonArray.size()];
for ( int i =0; i < strArray.length ; i++) {
strArray[i] = jsonArray.get(i).getAsString();
}
return strArray;
}
}
#Getter
#Setter
#ToString
public class ApplicationUsers {
private KeyValues users;
private KeyValues agents;
private KeyValues leads;
private KeyValues admins;
}
#Getter
#Setter
#ToString
public class KeyValues {
private String key;
private String[] values;
}
UsernamePasswordAuthenticationToken is asking for two arguments userid and password. But, I would like to pass userid, password as null, role of userid.

The purpose of InMemoryUserDetailsManager is just to represent user information in memory, it's userdetails service which is used by authentication provider. Ex:
#Bean
public InMemoryUserDetailsManager inMemoryUserDetailsManager() {
List<UserDetails> listOfUserDetails = new ArrayList<>();
listOfUserDetails.add(User.withUsername("userName").password(passwordEncoder().encode("pass"))
.roles("ADMIN", "LEAD","AGENT").build());
return new InMemoryUserDetailsManager(listOfUserDetails);
}
I do not think it is a good place to have authentication manipulations in InMemoryUserDetailsManager bean(It has different purpose).
Then register inMemoryUserDetailsManager bean to authenticationManagerBuilder:
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception
{
auth.userDetailsService(inMemoryUserDetailsManager());
}
As for UsernamePasswordAuthenticationToken, authentication provider after successful credential validation should return UsernamePasswordAuthenticationToken object built by 3 argument constructor as it sets authenticated flag to true.

I changed inMemoryUserDetailsManager() method and added passwordEncoder() method.
#Bean
public InMemoryUserDetailsManager inMemoryUserDetailsManager() {
final InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();
KeyValues kvAgents = orderDetailsUsers.applicatonUsers.getAgents();
String keyAgent = kvAgents.getKey();
String[] valueAgents = kvAgents.getValues();
for (int i = 0; i < valueAgents.length ; i++) {
manager.createUser(User.withUsername(valueAgents[i])
.password(passwordEncoder().encode(""))
.roles(keyAgent)
.build());
}
KeyValues kvAdmins = orderDetailsUsers.applicatonUsers.getAdmins();
String keyAdmin = kvAdmins.getKey();
String[] valueAdmins = kvAdmins.getValues();
for (int i = 0; i < valueAdmins.length ; i++) {
manager.createUser(User.withUsername(valueAdmins[i])
.password(passwordEncoder().encode(""))
.roles(keyAdmin)
.build());
}
KeyValues kvLeads = orderDetailsUsers.applicatonUsers.getLeads();
String keyLead = kvLeads.getKey();
String[] valueLeads = kvLeads.getValues();
for (int i = 0; i < valueLeads.length ; i++) {
manager.createUser(User.withUsername(valueLeads[i])
.password(passwordEncoder().encode(""))
.roles(keyLead)
.build());
}
return manager;
}
private PasswordEncoder passwordEncoder() {
return PasswordEncoderFactories.createDelegatingPasswordEncoder();
}

Related

Swagger 2 Feign client code oAuth flow throwing error url values must be not be absolute

I exposed Rest APIs, and I generated client code using Swagger 2 Java language with Feign library. The code gen generated the below OAuth RequestInterceptor. I am getting the below error when I use the oAuth as auth.
Error
feign.RetryableException: url values must be not be absolute.
at com.sam.feign.auth.OAuth.updateAccessToken(OAuth.java:95)
at com.sam.feign.auth.OAuth.apply(OAuth.java:83)
at feign.SynchronousMethodHandler.targetRequest(SynchronousMethodHandler.java:161)
at feign.SynchronousMethodHandler.executeAndDecode(SynchronousMethodHandler.java:110)
at feign.SynchronousMethodHandler.invoke(SynchronousMethodHandler.java:89)
at feign.ReflectiveFeign$FeignInvocationHandler.invoke(ReflectiveFeign.java:100)
at com.sun.proxy.$Proxy9.getUser(Unknown Source)
at com.sam.feign.clients.UserApiTest.getUserTest(UserApiTest.java:38)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:59)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:56)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
at org.junit.runners.BlockJUnit4ClassRunner$1.evaluate(BlockJUnit4ClassRunner.java:100)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:366)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:103)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:63)
at org.junit.runners.ParentRunner$4.run(ParentRunner.java:331)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:79)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:329)
at org.junit.runners.ParentRunner.access$100(ParentRunner.java:66)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:293)
at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
at org.junit.runners.ParentRunner.run(ParentRunner.java:413)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:86)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:538)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:760)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:460)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:206)
Caused by: java.lang.IllegalArgumentException: url values must be not be absolute.
at feign.RequestTemplate.uri(RequestTemplate.java:434)
at feign.RequestTemplate.uri(RequestTemplate.java:421)
at feign.RequestTemplate.append(RequestTemplate.java:388)
at com.sam.feign.auth.OAuth$OAuthFeignClient.execute(OAuth.java:163)
at org.apache.oltu.oauth2.client.OAuthClient.accessToken(OAuthClient.java:65)
at org.apache.oltu.oauth2.client.OAuthClient.accessToken(OAuthClient.java:55)
at org.apache.oltu.oauth2.client.OAuthClient.accessToken(OAuthClient.java:71)
at com.sam.feign.auth.OAuth.updateAccessToken(OAuth.java:93)
... 34 more
Swagger Generated oAuth supporting file
public class OAuth implements RequestInterceptor {
static final int MILLIS_PER_SECOND = 1000;
public interface AccessTokenListener {
void notify(BasicOAuthToken token);
}
private volatile String accessToken;
private Long expirationTimeMillis;
private OAuthClient oauthClient;
private TokenRequestBuilder tokenRequestBuilder;
private AuthenticationRequestBuilder authenticationRequestBuilder;
private AccessTokenListener accessTokenListener;
public OAuth(Client client, TokenRequestBuilder requestBuilder) {
this.oauthClient = new OAuthClient(new OAuthFeignClient(client));
this.tokenRequestBuilder = requestBuilder;
}
public OAuth(Client client, OAuthFlow flow, String authorizationUrl, String tokenUrl, String scopes) {
this(client, OAuthClientRequest.tokenLocation(tokenUrl).setScope(scopes));
switch(flow) {
case accessCode:
case implicit:
tokenRequestBuilder.setGrantType(GrantType.AUTHORIZATION_CODE);
break;
case password:
tokenRequestBuilder.setGrantType(GrantType.PASSWORD);
break;
case application:
tokenRequestBuilder.setGrantType(GrantType.CLIENT_CREDENTIALS);
break;
default:
break;
}
authenticationRequestBuilder = OAuthClientRequest.authorizationLocation(authorizationUrl);
}
public OAuth(OAuthFlow flow, String authorizationUrl, String tokenUrl, String scopes) {
this(new Client.Default(null, null), flow, authorizationUrl, tokenUrl, scopes);
}
#Override
public void apply(RequestTemplate template) {
// If the request already have an authorization (eg. Basic auth), do nothing
if (template.headers().containsKey("Authorization")) {
return;
}
// If first time, get the token
if (expirationTimeMillis == null || System.currentTimeMillis() >= expirationTimeMillis) {
updateAccessToken(template);
}
if (getAccessToken() != null) {
template.header("Authorization", "Bearer " + getAccessToken());
}
}
public synchronized void updateAccessToken(RequestTemplate template) {
OAuthJSONAccessTokenResponse accessTokenResponse;
try {
accessTokenResponse = oauthClient.accessToken(tokenRequestBuilder.buildBodyMessage());
} catch (Exception e) {
throw new RetryableException(400, e.getMessage(), template.request().httpMethod(), e, null, template.request());
}
if (accessTokenResponse != null && accessTokenResponse.getAccessToken() != null) {
setAccessToken(accessTokenResponse.getAccessToken(), accessTokenResponse.getExpiresIn());
if (accessTokenListener != null) {
accessTokenListener.notify((BasicOAuthToken) accessTokenResponse.getOAuthToken());
}
}
}
public synchronized void registerAccessTokenListener(AccessTokenListener accessTokenListener) {
this.accessTokenListener = accessTokenListener;
}
public synchronized String getAccessToken() {
return accessToken;
}
public synchronized void setAccessToken(String accessToken, Long expiresIn) {
this.accessToken = accessToken;
this.expirationTimeMillis = System.currentTimeMillis() + expiresIn * MILLIS_PER_SECOND;
}
public TokenRequestBuilder getTokenRequestBuilder() {
return tokenRequestBuilder;
}
public void setTokenRequestBuilder(TokenRequestBuilder tokenRequestBuilder) {
this.tokenRequestBuilder = tokenRequestBuilder;
}
public AuthenticationRequestBuilder getAuthenticationRequestBuilder() {
return authenticationRequestBuilder;
}
public void setAuthenticationRequestBuilder(AuthenticationRequestBuilder authenticationRequestBuilder) {
this.authenticationRequestBuilder = authenticationRequestBuilder;
}
public OAuthClient getOauthClient() {
return oauthClient;
}
public void setOauthClient(OAuthClient oauthClient) {
this.oauthClient = oauthClient;
}
public void setOauthClient(Client client) {
this.oauthClient = new OAuthClient( new OAuthFeignClient(client));
}
public static class OAuthFeignClient implements HttpClient {
private Client client;
public OAuthFeignClient() {
this.client = new Client.Default(null, null);
}
public OAuthFeignClient(Client client) {
this.client = client;
}
public <T extends OAuthClientResponse> T execute(OAuthClientRequest request, Map<String, String> headers,
String requestMethod, Class<T> responseClass)
throws OAuthSystemException, OAuthProblemException {
RequestTemplate req = new RequestTemplate()
.append(request.getLocationUri())
.method(requestMethod)
.body(request.getBody());
for (Entry<String, String> entry : headers.entrySet()) {
req.header(entry.getKey(), entry.getValue());
}
Response feignResponse;
String body = "";
try {
feignResponse = client.execute(req.request(), new Options());
body = Util.toString(feignResponse.body().asReader());
} catch (IOException e) {
throw new OAuthSystemException(e);
}
String contentType = null;
Collection<String> contentTypeHeader = feignResponse.headers().get("Content-Type");
if(contentTypeHeader != null) {
contentType = StringUtil.join(contentTypeHeader.toArray(new String[0]), ";");
}
return OAuthClientResponseFactory.createCustomResponse(
body,
contentType,
feignResponse.status(),
responseClass
);
}
public void shutdown() {
// Nothing to do here
}
}
}
ApiClient.java have the below absolute URL which configured in swagger spec
public ApiClient() {
objectMapper = createObjectMapper();
apiAuthorizations = new LinkedHashMap<String, RequestInterceptor>();
feignBuilder = Feign.builder()
.encoder(new FormEncoder(new JacksonEncoder(objectMapper)))
.decoder(new JacksonDecoder(objectMapper))
.logger(new Slf4jLogger());
}
public ApiClient(String[] authNames) {
this();
for(String authName : authNames) {
RequestInterceptor auth = null;
if ("client-credentils-oauth2".equals(authName)) {
auth = new OAuth(OAuthFlow.application, "", "http://localhost:8080/app/oauth/token", "user.create");
} else if ("password-oauth2".equals(authName)) {
auth = new OAuth(OAuthFlow.password, "", "http://localhost:8080/app/oauth/token", "openid");
} else {
throw new RuntimeException("auth name \"" + authName + "\" not found in available auth names");
}
addAuthorization(authName, auth);
}
}
Used the below dependencies
swagger-codegen-maven-plugin v2.4.28
feign-version 11.6
feign-form-version 3.8.0
oltu-version 1.0.1
Java 8
I am invoking the client by using below code
UserApi api = new ApiClient("client-credentils-oauth2","admin", "admin", null, null).buildClient(UserApi.class);
api.getUser(login, tenant)
I made the few changes in the generated oAuth.java file to make it work. Expecting the client generated code should work without making any manual changes.
public <T extends OAuthClientResponse> T execute(OAuthClientRequest request, Map<String, String> headers,
String requestMethod, Class<T> responseClass)
throws OAuthSystemException, OAuthProblemException {
// Added the below 3 lines
URI targetUri = URI.create(uri);
String target = targetUri.getScheme() + "://" + targetUri.getAuthority() ;
String path = targetUri.getPath();
RequestTemplate req = new RequestTemplate()
.uri(path)
.method(requestMethod)
.body(request.getBody())
.target(target); // Added this line
for (Entry<String, String> entry : headers.entrySet()) {
req.header(entry.getKey(), entry.getValue());
}
req = req.resolve(new HashMap<String, Object>()); // Added this line
Response feignResponse;
String body = "";
try {
feignResponse = client.execute(req.request(), new Options());
body = Util.toString(feignResponse.body().asReader());
} catch (IOException e) {
throw new OAuthSystemException(e);
}
String contentType = null;
Collection<String> contentTypeHeader = feignResponse.headers().get("Content-Type");
if(contentTypeHeader != null) {
contentType = StringUtil.join(contentTypeHeader.toArray(new String[0]), ";");
}
return OAuthClientResponseFactory.createCustomResponse(
body,
contentType,
feignResponse.status(),
responseClass
);
}
Appreciate if someone can assist me with this issue

Auto-provisioning device under an enrolment group does not work (java SDK)

I've performed this example
https://learn.microsoft.com/en-us/azure/iot-dps/quick-enroll-device-x509-java
It does not appear under "registration records" under the enrolment group but it throws this error:
PROVISIONING_DEVICE_STATUS_FAILED, Exception: com.microsoft.azure.sdk.iot.provisioning.device.internal.exceptions.ProvisioningDeviceHubException: Signing certificate info did not match chain elements
Registration:
public class DeviceRegistration {
String idScope;
String globalEndpoint;
String clientCert;
String clientCertPrivateKey;
String signerCert;
public DeviceRegistration(String idScope, String globalEndpoint, String clientCert, String clientCertPrivateKey, String signerCert) {
this.idScope = idScope;
this.globalEndpoint = globalEndpoint;
this.clientCert = clientCert;
this.clientCertPrivateKey = clientCertPrivateKey;
this.signerCert = signerCert;
}
public void register(ProvisioningDeviceClientRegistrationCallback callback) throws Exception {
Collection<String> signerCertificates = new LinkedList<>();
signerCertificates.add(signerCert);
ProvisioningDeviceClient provisioningDeviceClient = null;
SecurityProvider securityProviderX509 = new SecurityProviderX509Cert(clientCert, clientCertPrivateKey, signerCertificates);
provisioningDeviceClient = ProvisioningDeviceClient.create(globalEndpoint, idScope, ProvisioningDeviceClientTransportProtocol.HTTPS,
securityProviderX509);
provisioningDeviceClient.registerDevice(callback, this);
}
private static String loadFile(String filename) throws Exception {
File f = new File(filename);
if (!f.exists())
throw new Exception("File not found: " + filename);
BufferedReader reader = new BufferedReader(new FileReader(f));
char[] buffer = new char[(int) f.length()];
reader.read(buffer);
reader.close();
return new String(buffer);
}
public static void main(String[] args){
try {
CountDownLatch countDownLatch = new CountDownLatch(1);
DeviceRegistration deviceRegistration = new DeviceRegistration(args[0], args[1], loadFile(args[2]), loadFile(args[3]), loadFile(args[4]));
deviceRegistration.register(new ProvisioningDeviceClientRegistrationCallback() {
#Override
public void run(ProvisioningDeviceClientRegistrationResult provisioningDeviceClientRegistrationResult, Exception e, Object context) {
if (provisioningDeviceClientRegistrationResult.getProvisioningDeviceClientStatus() == ProvisioningDeviceClientStatus.PROVISIONING_DEVICE_STATUS_ASSIGNED) {
System.out.println("IotHUb Uri : " + provisioningDeviceClientRegistrationResult.getIothubUri());
System.out.println("Device ID : " + provisioningDeviceClientRegistrationResult.getDeviceId());
countDownLatch.countDown();
} else {
System.out.println("Result: "+provisioningDeviceClientRegistrationResult.getProvisioningDeviceClientStatus()+", Exception: "+e);
}
}
});
countDownLatch.await();
} catch (Exception e) {
e.printStackTrace();
}
}}
Delete the individual enrollment and make sure that you've gone through the verification of your X.509 signing cert (in the Certificates tab in the Azure portal). If you have both an enrollment group and an individual enrollment for a device, the individual enrollment takes precedence.

Xamarin.Auth - Google OAuth don't close over UWP when IsUsingNativeUI is set to true

I just implemented Xamarin.Auth on UWP, and I have a weird problem.
I begin by creating my OAuth object :
public class OAuth
{
private Account account;
private AccountStore store;
public string Scope;
public string AuthorizeUrl;
public string AccessTokenUrl;
public string UserInfoUrl;
string clientId;
string clientSecret;
string redirectUri;
private bool isUsingNativeUI;
private Func<JObject, User> OAuthParser;
private Action<User> OnCompleted;
private Action<string> OnError;
public OAuth()
{
account = null;
store = null;
Scope = "";
AuthorizeUrl = "";
AccessTokenUrl = "";
UserInfoUrl = "";
clientId = "";
clientSecret = null;
redirectUri = "";
}
public OAuth Facebook()
{
// These values do not need changing
Scope = "email";
AuthorizeUrl = "https://www.facebook.com/v2.8/dialog/oauth";
AccessTokenUrl = "https://graph.facebook.com/oauth/access_token";
UserInfoUrl = "https://graph.facebook.com/me?fields=email,name,gender,picture";
clientId = "xxxx";
clientSecret = "xxxxx";
redirectUri = "http://www.facebook.com/connect/login_success.html";
isUsingNativeUI = false;
OAuthParser = ParseFacebookResponse;
return this;
}
public OAuth GooglePlus()
{
// These values do not need changing
Scope = "https://www.googleapis.com/auth/userinfo.email";
AuthorizeUrl = "https://accounts.google.com/o/oauth2/auth";
AccessTokenUrl = "https://www.googleapis.com/oauth2/v4/token";
UserInfoUrl = "https://www.googleapis.com/oauth2/v2/userinfo";
clientId = "xxxxx";
redirectUri = "xxxxxx";
isUsingNativeUI = true;
OAuthParser = ParseGooglePlusResponse;
return this;
}
public OAuth2Authenticator Authenticator(Action<User> onCompleted, Action<string> onError)
{
OAuth2Authenticator authenticator = new OAuth2Authenticator(
clientId,
clientSecret,
Scope,
new Uri(AuthorizeUrl),
new Uri(redirectUri),
new Uri(AccessTokenUrl),
null,
isUsingNativeUI);
authenticator.Completed += OnAuthCompleted;
authenticator.Error += OnAuthError;
OnCompleted = onCompleted;
OnError = onError;
return authenticator;
}
private async void OnAuthCompleted(object sender, AuthenticatorCompletedEventArgs e)
{
User user = null;
try
{
OAuth2Authenticator OAuth2Authenticator = sender as OAuth2Authenticator;
if (OAuth2Authenticator != null)
{
OAuth2Authenticator.Completed -= OnAuthCompleted;
OAuth2Authenticator.Error -= OnAuthError;
}
//User user = null;
if (e.IsAuthenticated)
{
var request = new OAuth2Request("GET", new Uri(UserInfoUrl), null, e.Account);
var response = await request.GetResponseAsync();
if (response != null)
{
user = OAuthParser(JObject.Parse(await response.GetResponseTextAsync()));
}
if (account != null)
{
store.Delete(account, App.AppName);
}
await store.SaveAsync(account = e.Account, App.AppName);
}
} catch (Exception ex) {
Debug.WriteLine(ex);
}
(Application.Current.MainPage as LoginPage).OAuthCompleted(user);
}
private void OnAuthError(object sender, AuthenticatorErrorEventArgs e)
{
OAuth2Authenticator OAuth2Authenticator = sender as OAuth2Authenticator;
if (OAuth2Authenticator != null)
{
OAuth2Authenticator.Completed -= OnAuthCompleted;
OAuth2Authenticator.Error -= OnAuthError;
}
(Application.Current.MainPage as LoginPage).OAuthError("Authentication error: " + e.Message);
}
private static User ParseGooglePlusResponse(JObject jobject)
{
try
{
User user = new User()
{
Email = jobject["email"].ToString(),
Pseudo = jobject["name"].ToString(),
Firstname = jobject["given_name"].ToString(),
Surname = jobject["family_name"].ToString(),
Image = jobject["picture"].ToString(),
Password = "girafe"
};
return user;
}
catch (Exception e)
{ Debug.WriteLine(e.ToString()); }
return null;
}
private static User ParseFacebookResponse(JObject jobject)
{
try
{
Debug.WriteLine(jobject);
User user = new User()
{
Email = jobject["email"].ToString(),
Pseudo = jobject["name"].ToString(),
Image = jobject["picture"]["data"]["url"].ToString(),
Password = "girafe"
};
return user;
}
catch (Exception e)
{ Debug.WriteLine(e.ToString()); }
return null;
}
}
And I use it like that:
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class LoginPage : ContentPage, INotifyPropertyChanged
{
private OAuth OAuthService;
private OAuthLoginPresenter Presenter;
// ...
private void FacebookAuthConnection()
{
AuthenticationState.Authenticator = OAuthService.Facebook().Authenticator(OAuthCompleted, OAuthError);
Presenter.Login(AuthenticationState.Authenticator);
}
private void GooglePlusAuthConnection()
{
AuthenticationState.Authenticator = OAuthService.GooglePlus().Authenticator(OAuthCompleted, OAuthError);
Presenter.Login(AuthenticationState.Authenticator);
}
// ...
}
On Android, either if isUsingNativeUI is set to true or false, after I connect myself, the webview/oauth get closed. Over UWP however, it doesn't work when isUsingNativeUI is set to true, the webview/oauth don't close, so I'm navigating on google and I am not able to come back on the app (UWP Desktop)...
Do you have any idea?

Posting to HTTPS in Java

I want to post to an url https://host:0101 with a request body. I have done this with non-ssl, http, but having trouble with https.
I have both the trust store (JKS) and keystore (PKCS12)'s full path, and their passwords as properties in a .properties file.
What i have to far is:
public sendPost () throws Exception {
SSLContext sslContext = getContext();
SSLConnectionSocketFactory factory = new SSLConnectionSocketFactory(sslContext, SSLConnectionSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);
CloseableHttpClient client = HttpClients.custom().setSSLSocketFactory(factory).build();
HttpPost post = new HttpPost("https://host:0101/post");
StringEntity entity = new StringEntity(jsonData);
post.setEntity(entity);
response=client.execute(request);
responseCode = response.getStatusLine().getStatusCode();
}
public SSLContext getContext() throws Exception {
KeyStore keyStore = KeyStore.getInstance("JKS");
FileInputStream instream = new FileInputStream(new File(PATH_TO_KEYSTORE));
try {
keyStore.load(instream, "password".toCharArray());
}finally {instream.close()}
return SSLContexts.custom().loadTrustMaterial(keyStore).build();
}
I am testing this by running a Junit test just to verify that it works before deploying.
#Test
public void test() throws Exception {
int responseCode = entityUnderTest.sendPost();
assertEquals(200, responseCode);
}
The error is at line: response=client.execute(request); with the HttpHostConnectException
Failed: Connection Refused
Is the service available through HTTPS? The connection refused error occurs when there is some problem with the availability of your service.
This could be caused by a lot of problems:
your service is not running
your service is not available through HTTPS
a proxy/routing error (does your test system reach the host and port?)
If there was a problem with the authentication you would get a different message (eg: SSLPeerUnverifiedException, SSLHandshakeException).
This is working for me.. try it
Here is the post method
public static CookieManager msCookieManager = null;
private boolean isPinBuild=false;
public static String[] post(Context context, String Url, List<NameValuePair> values, List<NameValuePair> header_list)
throws ConnectTimeoutException {
String[] result = { "", "" };
try {
URL url = new URL(Url);
HttpsURLConnection urlConnection = (HttpsURLConnection) url.openConnection();
Log.i("TAG_URL : ", Url);
if (isPinBuild) {
KeyPinStore keystore = KeyPinStore.getInstance(context);
javax.net.ssl.SSLSocketFactory factory = keystore.getContext().getSocketFactory();
SSLSocket socket = (SSLSocket)factory.createSocket();
socket.setEnabledCipherSuites(new String[]{"RC4-MD5", "DES-CBC-SHA", "DES-CBC3-SHA"});
socket.setEnabledProtocols(new String[] {"TLSv1.1", "TLSv1.2"});
socket.setSoTimeout(60000);
urlConnection.setSSLSocketFactory(factory);
} else {
KeyUnPinStore keystore = KeyUnPinStore.getInstance(context);
javax.net.ssl.SSLSocketFactory factory = keystore.getContext().getSocketFactory();
SSLSocket socket = (SSLSocket)factory.createSocket();
socket.setEnabledCipherSuites(new String[]{"RC4-MD5", "DES-CBC-SHA", "DES-CBC3-SHA"});
socket.setEnabledProtocols(new String[] {"TLSv1.1", "TLSv1.2"});
socket.setSoTimeout(60000);
urlConnection.setSSLSocketFactory(factory);
}
HostnameVerifier hostnameVerifier = org.apache.http.conn.ssl.SSLSocketFactory.STRICT_HOSTNAME_VERIFIER;
urlConnection.setRequestMethod("POST");
urlConnection.setConnectTimeout(connection_timeout);
urlConnection.setHostnameVerifier(hostnameVerifier);
urlConnection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
for (NameValuePair header : header_list) {
urlConnection.addRequestProperty(header.getName(), header.getValue());
}
if (msCookieManager == null) {
msCookieManager = new CookieManager();
}
if (msCookieManager != null && msCookieManager.getCookieStore().getCookies().size() > 0) {
urlConnection.setRequestProperty(COOKIE, TextUtils.join(";", msCookieManager.getCookieStore().getCookies()));
}
Log.i("TAG_POST_COOKIE : ", msCookieManager.getCookieStore().getCookies().toString());
String postData = "";
for (NameValuePair value : values) {
postData = postData + value.getName() + "=" + URLEncoder.encode(value.getValue(), "UTF-8") + "&";
}
if (!TextUtils.isEmpty(postData) && postData.length() > 2) {
postData = postData.substring(0, postData.length() - 1);
}
Log.i("TAG_POSTDATA : ", postData);
urlConnection.setUseCaches(false);
urlConnection.setDoInput(true);
urlConnection.setDoOutput(true);
urlConnection.setFixedLengthStreamingMode(postData.getBytes().length);
PrintWriter out = new PrintWriter(urlConnection.getOutputStream());
out.print(postData);
out.close();
// always check HTTP response code first
int responseCode = urlConnection.getResponseCode();
result[0] = responseCode + "";
if (responseCode == HttpURLConnection.HTTP_OK) {
// Get Response
InputStream is = urlConnection.getInputStream();
BufferedReader rd = new BufferedReader(new InputStreamReader(is));
String line;
StringBuffer response = new StringBuffer();
while ((line = rd.readLine()) != null) {
response.append(line);
response.append('\r');
}
rd.close();
Map<String, List<String>> headerFields = urlConnection.getHeaderFields();
List<String> cookiesHeader = headerFields.get(COOKIES_HEADER);
/*if (cookiesHeader != null) {
for (String cookie : cookiesHeader) {
if (HttpCookie.parse(cookie).get(0).toString().contains(JSESSIONID)) {
msCookieManager.getCookieStore().add(null, HttpCookie.parse(cookie).get(0));
}
}
}*/
if (!TextUtils.isEmpty(response)) {
result[0] = HttpConnectionUrl.RESPONSECODE_REQUESTSUCCESS;
result[1] = response.toString();
Log.i("TAG_RESPONSE : ", result[1]);
}
}
} catch (UnsupportedEncodingException e) {
result[0] = HttpConnectionUrl.RESPONSECODE_CONNECTIONTIMEOUT;
e.printStackTrace();
} catch (ClientProtocolException e) {
result[0] = HttpConnectionUrl.RESPONSECODE_CONNECTIONTIMEOUT;
e.printStackTrace();
} catch (ConnectTimeoutException e) {
result[0] = HttpConnectionUrl.RESPONSECODE_CONNECTIONTIMEOUT;
e.printStackTrace();
} catch (IOException e) {
result[0] = HttpConnectionUrl.RESPONSECODE_CONNECTIONTIMEOUT;
e.printStackTrace();
} catch (Exception e) {
result[0] = HttpConnectionUrl.RESPONSECODE_CONNECTIONTIMEOUT;
e.printStackTrace();
}
return result;
}
here isPinBuild variable use for you have any certificate file or not. If you use any trusted certificate then set true.
Here the KeyPinStore class
public class KeyPinStore {
private static Context context = null;
private static KeyPinStore instance = null;
private SSLContext sslContext = SSLContext.getInstance("SSLv3");
//private SSLContext sslContext = SSLContext.getInstance("TLS");
public static synchronized KeyPinStore getInstance(Context mContext) throws CertificateException, IOException, KeyStoreException,
NoSuchAlgorithmException, KeyManagementException {
if (instance == null) {
context = mContext;
instance = new KeyPinStore();
}
return instance;
}
private KeyPinStore() throws CertificateException, IOException, KeyStoreException, NoSuchAlgorithmException, KeyManagementException {
// Load CAs from an InputStream
// (could be from a resource or ByteArrayInputStream or ...)
CertificateFactory cf = CertificateFactory.getInstance("X.509");
// randomCA.crt should be in the Assets directory
InputStream caInput = new BufferedInputStream(context.getAssets().open("yourCertificate.crt"));
Certificate ca;
try {
ca = cf.generateCertificate(caInput);
System.out.println("ca=" + ((X509Certificate) ca).getSubjectDN());
} finally {
caInput.close();
}
// Create a KeyStore containing our trusted CAs
String keyStoreType = KeyStore.getDefaultType();
KeyStore keyStore = KeyStore.getInstance(keyStoreType);
keyStore.load(null, null);
keyStore.setCertificateEntry("ca", ca);
// Create a TrustManager that trusts the CAs in our KeyStore
String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmfAlgorithm);
tmf.init(keyStore);
// Create an SSLContext that uses our TrustManager
// SSLContext context = SSLContext.getInstance("TLS");
sslContext.init(null, tmf.getTrustManagers(), null);
}
public SSLContext getContext() {
return sslContext;
}
}
and KeyUnpinStore class
public class KeyUnPinStore {
private static Context context = null;
private static KeyUnPinStore instance = null;
private SSLContext sslContext = SSLContext.getInstance("TLS");
public static synchronized KeyUnPinStore getInstance(Context mContext) throws CertificateException, IOException, KeyStoreException,
NoSuchAlgorithmException, KeyManagementException {
if (instance == null) {
context = mContext;
instance = new KeyUnPinStore();
}
return instance;
}
private KeyUnPinStore() throws CertificateException, IOException, KeyStoreException, NoSuchAlgorithmException, KeyManagementException {
// Create a trust manager that does not validate certificate chains
TrustManager[] trustAllCerts = new TrustManager[] { new X509TrustManager() {
public X509Certificate[] getAcceptedIssuers() {
return null;
}
public void checkClientTrusted(X509Certificate[] certs, String authType) {
}
public void checkServerTrusted(X509Certificate[] certs, String authType) {
}
} };
// Create all-trusting host name verifier
// Create an SSLContext that uses our TrustManager
// SSLContext context = SSLContext.getInstance("TLS");
sslContext.init(null, trustAllCerts, new java.security.SecureRandom());
}
public SSLContext getContext() {
return sslContext;
}
}
Why don't you try using httpbin? It's an external resource that's guaranteed to work. For example:
import java.io.IOException;
import java.net.URI;
import net.minidev.json.JSONObject;
import net.minidev.json.JSONValue;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.util.EntityUtils;
public class Post {
public static void main(String[] args) throws Exception {
HttpClient client = new DefaultHttpClient();
int result = post(client, new URI("https://httpbin.org/post"), (JSONObject)JSONValue.parse("{'answer':42}"));
System.err.println(result);
}
public static int post(HttpClient httpClient, URI url, JSONObject content) throws IOException {
final HttpPost post = new HttpPost(url);
post.addHeader("Content-type", ContentType.APPLICATION_JSON.getMimeType());
post.setEntity(new StringEntity(content.toString(), ContentType.APPLICATION_JSON));
final HttpResponse response = httpClient.execute(post);
EntityUtils.consumeQuietly(response.getEntity());
return response.getStatusLine().getStatusCode();
}
}
Assuming that you have generated public/private keypairs using java "keytool" and both trustStore & keyStores are configured properly at client-side & in HOST container(in case of Tomcat server.xml).
In Method:"sendPost()", you may like to get SSL-Connection as follows:
try {
String endpoint="https://host:0101/post";
URL url = new URL(endpoint);
HttpsURLConnection conn = getConnection(url, "POST", uname, passwd);
conn.connect();
writeBody(conn);
catch(Exception e) { throw new RuntimeException(e); }
conn.disconnect();
}
catch(Exception e) { throw new RuntimeException(e); }
private void writeBody(HttpsURLConnection conn) {
try {
String pairs = "who=Freddy&what=Avoid Friday nights if possible.";
OutputStream out = conn.getOutputStream();
out.write(pairs.getBytes());
out.flush();
}
catch(Exception e) { throw new RuntimeException(e); }
}

Cannot find com.intuit.utils.OauthHelper class for Android application

I want to integrate QuickBooks api into our android application.
Below link is for Java Web Application but I want to this OauthHelper class in my android application.
https://github.com/IntuitDeveloperRelations/QuickbooksV3API-Java/blob/master/QuickbooksV3API/src/main/java/com/intuit/utils/OauthHelper.java
I also saw developer site of Intuit but it does not help,
https://intuitpartnerplatform.lc.intuit.com/questions/825445-can-t-find-com-intuit-ia-connection-oauthhelper-class
Is there is a new way to do it or any latest jar file which contain OauthHelper class?
JAR File
You have to add this jar ipp-v3-java-devkit-2.3.2-jar-with-dependencies, you can download from this link.
OauthHelper Class
public class OauthHelper {
public static String REQUEST_TOKEN_URL;
public static String ACCESS_TOKEN_URL;
public static String AUTHORIZE_URL;
public OauthHelper() {
REQUEST_TOKEN_URL = Constants.OAUTH_URL + "/oauth/v1/get_request_token";
ACCESS_TOKEN_URL = Constants.OAUTH_URL + "/oauth/v1/get_access_token";
AUTHORIZE_URL = Constants.APPCENTER_URL + "/Connect/Begin";
}
public void getDynamicConsumer() {
try {
final String apptoken = Constants.APP_TOKEN;
final URL url = new URL(Constants.OAUTH_URL
+ "/oauth/v1/create_consumer?appToken=" + apptoken);
final HttpURLConnection httpconnection = (HttpURLConnection) url
.openConnection();
httpconnection.connect();
StringBuffer responseBody = null;
int read = 0;
final byte buffer[] = new byte[8192];
String consumerret = "";
String consumerkeytoken = "";
String consumerkeysecret = "";
try {
final InputStream responseBodyStream = httpconnection
.getInputStream();
responseBody = new StringBuffer();
while ((read = responseBodyStream.read(buffer)) != -1) {
responseBody.append(new String(buffer, 0, read));
}
responseBodyStream.close();
consumerret = responseBody.toString();
final String[] consumerkey = consumerret.split("&");
for (int i = 0; i < consumerkey.length; i++) {
final String[] currentElements = consumerkey[i].split("=");
if (currentElements[0].equalsIgnoreCase("oauth_token")) {
consumerkeytoken = currentElements[1];
} else if (currentElements[0]
.equalsIgnoreCase("oauth_token_secret")) {
consumerkeysecret = currentElements[1];
}
}
} catch (Exception ex1) {
final int httpRespCode = httpconnection.getResponseCode();
try {
final InputStream es = httpconnection.getErrorStream();
final StringBuffer errorBody = new StringBuffer();
while ((read = es.read(buffer)) != -1) {
errorBody.append(new String(buffer, 0, read));
}
} catch (Exception ex2) {
ex2.printStackTrace();
}
}
} catch (Exception ex3) {
ex3.printStackTrace();
}
}
public Map<String, String> getRequestTokenSignPost() {
String authURL = null;
OAuthProvider provider = createProvider();
String consumerkey = Constants.CONSUMER_KEY;
String consumersecret = Constants.CONSUMER_SECRET;
String callback_url = Constants.CALLBACK_URL;// WebUtils.OAUTH_CALLBACK_URL;
OAuthConsumer ouathconsumer = new DefaultOAuthConsumer(consumerkey,
consumersecret);
try {
HttpParameters additionalParams = new HttpParameters();
additionalParams.put("oauth_callback",
URLEncoder.encode(callback_url, "UTF-8"));
ouathconsumer.setAdditionalParameters(additionalParams);
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
String requestret = "";
String requestToken = "";
String requestTokenSecret = "";
try {
String signedRequestTokenUrl = ouathconsumer
.sign(REQUEST_TOKEN_URL);
URL url;
url = new URL(signedRequestTokenUrl);
HttpURLConnection httpconnection = (HttpURLConnection) url
.openConnection();
httpconnection.setRequestMethod("GET");
httpconnection
.setRequestProperty("Content-type", "application/xml");
httpconnection.setRequestProperty("Content-Length", "0");
if (httpconnection != null) {
BufferedReader rd = new BufferedReader(new InputStreamReader(
httpconnection.getInputStream()));
StringBuffer sb = new StringBuffer();
String line;
while ((line = rd.readLine()) != null) {
sb.append(line);
}
rd.close();
requestret = sb.toString();
}
String[] requestTokenSections = requestret.split("&");
for (int i = 0; i < requestTokenSections.length; i++) {
String[] currentElements = requestTokenSections[i].split("=");
if (currentElements[0].equalsIgnoreCase("oauth_token")) {
requestToken = currentElements[1];
} else if (currentElements[0]
.equalsIgnoreCase("oauth_token_secret")) {
requestTokenSecret = currentElements[1];
}
}
Map<String, String> requesttokenmap = new HashMap<String, String>();
try {
authURL = provider.retrieveRequestToken(ouathconsumer,
callback_url);
} catch (OAuthNotAuthorizedException e) {
e.printStackTrace();
}
ouathconsumer.setTokenWithSecret(ouathconsumer.getToken(),
ouathconsumer.getTokenSecret());
requesttokenmap.put("requestToken", requestToken);
requesttokenmap.put("requestTokenSecret", requestTokenSecret);
requesttokenmap.put("authURL", authURL);
return requesttokenmap;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
public static OAuthProvider createProvider() {
OAuthProvider provider = new DefaultOAuthProvider(
OauthHelper.REQUEST_TOKEN_URL, OauthHelper.ACCESS_TOKEN_URL,
OauthHelper.AUTHORIZE_URL);
return provider;
}
public String getAuthorizeURL(String requestToken, String requestTokenSecret) {
String authorizeURL = "";
try {
authorizeURL = AUTHORIZE_URL + "?oauth_token=" + requestToken;
} catch (Exception e) {
e.printStackTrace();
}
return authorizeURL;
}
public Map<String, String> getAccessToken(String verifierCode,
String requestToken, String requestTokenSecret) {
String consumerkey = Constants.CONSUMER_KEY;
String consumersecret = Constants.CONSUMER_SECRET;
String accessToken = "";
String accessTokenSecret = "";
try {
OAuthConsumer consumer = new DefaultOAuthConsumer(consumerkey,
consumersecret);
consumer.setTokenWithSecret(requestToken, requestTokenSecret);
HttpParameters additionalParams = new HttpParameters();
additionalParams.put("oauth_callback", "oob");
additionalParams.put("oauth_verifier", verifierCode);
consumer.setAdditionalParameters(additionalParams);
String signedURL = consumer.sign(ACCESS_TOKEN_URL);
URL url = new URL(signedURL);
HttpURLConnection urlConnection = (HttpURLConnection) url
.openConnection();
urlConnection.setRequestMethod("GET");
urlConnection.setRequestProperty("Content-type", "application/xml");
urlConnection.setRequestProperty("Content-Length", "0");
String accesstokenresponse = "";
if (urlConnection != null) {
BufferedReader rd = new BufferedReader(new InputStreamReader(
urlConnection.getInputStream()));
StringBuffer sb = new StringBuffer();
String line;
while ((line = rd.readLine()) != null) {
sb.append(line);
}
rd.close();
accesstokenresponse = sb.toString();
}
if (accesstokenresponse != null) {
String[] responseElements = accesstokenresponse.split("&");
if (responseElements.length > 1) {
accessToken = responseElements[1].split("=")[1];
accessTokenSecret = responseElements[0].split("=")[1];
Map<String, String> accesstokenmap = new HashMap<String, String>();
accesstokenmap.put("accessToken", accessToken);
accesstokenmap.put("accessTokenSecret", accessTokenSecret);
return accesstokenmap;
}
}
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
Constants Class
public class Constants {
public static final String APP_TOKEN = ""; // First three credentials are from **Production** part not from **Development** part
public static final String CONSUMER_KEY = "";
public static final String CONSUMER_SECRET = "";
public static final String REQUEST_TOKEN_URL = "https://oauth.intuit.com/oauth/v1/get_request_token";
public static final String AUTH_URL = "https://appcenter.intuit.com/Connect/Begin";
public static final String ACCESS_TOKEN_URL = "https://oauth.intuit.com/oauth/v1/get_access_token";
public static final String OAUTH_CALLBACK_SCHEME = "oauthflow-quickbooks";
public static final String OAUTH_CALLBACK_HOST = "callback";
public static final String CALLBACK_URL = OAUTH_CALLBACK_SCHEME + "://"
+ OAUTH_CALLBACK_HOST;
public static final String PREFERENCE_NAME = "quickbooks";
public static String OAUTH_URL = "https://oauth.intuit.com";
public static String APPCENTER_URL = "https://appcenter.intuit.com";
}
Manifest file
Add following intent filter to activity when login is initiated.
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data
android:host="callback"
android:scheme="oauthflow-quickbooks" />
</intent-filter>

Resources