I want to update programmatically the parameter from the Firebase Remote Config - android

This is the code that I have:
final FirebaseRemoteConfig config = FirebaseRemoteConfig.getInstance();
FirebaseRemoteConfigSettings configSettings = new FirebaseRemoteConfigSettings.Builder()
.setDeveloperModeEnabled(BuildConfig.DEBUG)
.build();
config.setConfigSettings(configSettings);
config.fetch(0).addOnCompleteListener(new OnCompleteListener<Void>() {
#Override
public void onComplete(#NonNull Task<Void> task) {
if (task.isSuccessful()) {
// After config data is successfully fetched, it must be activated before newly fetched
// values are returned.
config.activateFetched();
final String playStoreVersionCode = FirebaseRemoteConfig.getInstance().getString(
"android_latest_version_code");
} else {
Utils.appendLog("playStoreVersionCode Error fetching latest params ", "E", Constants.TIMELINE);
}
}
});
Now I want to increment my parameter, and I saw that from March there is a REST API in order to update parameters:
https://firebase.google.com/docs/remote-config/api-overview
https://firebase.google.com/docs/remote-config/use-config-rest
But I don't really understand the tutorial.
Why do I need to use curl? is this really necessary like in the use-config-rest link?
curl --compressed -D headers -H "Authorization: Bearer token" -X GET https://firebaseremoteconfig.googleapis.com/v1/projects/my-project-id/remoteConfig -o filename
And the quickstart just shows an example on how to fetch the data, not change it:
https://github.com/firebase/quickstart-android/blob/master/config/app/src/main/java/com/google/samples/quickstart/config/MainActivity.java

Remote Config parameters aren't meant to be changed from client code. They're only meant to be read on the client. If you want to change thing programmatically, you're supposed to do that from a server your control.
If you want a read/write some persisted value in your app, don't use Remote Config. Use Realtime Database or Firestore instead.
The reason for showing curl commands in the documentation is to illustrate how to make the HTTP request using a command that many people are familiar with. You can make the HTTP request any way you want, as long as you follow the specification.

Related

Deleting a user from Azure Active Directory B2C Android/Java

I have an Android application in which I'm using Azure AD B2C to authenticate users. Users login and logout of the application as needed. I would like to give the user the option to delete their own account.
I understand that I need to use the Azure AD Graph API to delete the user. This is what I have so far:
According to this link, it looks like deleting a user from a personal account (which is what the B2C users are using) is not possible. Is that correct?
Here's my code snippet for the Graph API call. Feel free to ignore it if I'm off track and there is a better way to solve this.
I believe I need a separate access token than what my app currently has (as the graph API requires other API consent). So, I'm getting the access token as follows:
AcquireTokenParameters parameters = new AcquireTokenParameters.Builder()
.startAuthorizationFromActivity(getActivity())
.fromAuthority(B2CConfiguration.getAuthorityFromPolicyName(B2CConfiguration.Policies.get("SignUpSignIn")))
.withScopes(B2CConfiguration.getGraphAPIScopes())
.withPrompt(Prompt.CONSENT)
.withCallback(getGraphAPIAuthCallback())
.build();
taxApp.acquireToken(parameters);
In the getGraphAPIAuthCallback() method, I'm calling the Graph API using a separate thread (in the background):
boolean resp = new DeleteUser().execute(authenticationResult.getAccessToken()).get();
Finally, in my DeleterUser() AsyncTask, I'm doing the following:
#Override
protected Boolean doInBackground(String... aToken) {
final String asToken = aToken[0];
//this method will be running on background thread so don't update UI from here
//do your long running http tasks here,you dont want to pass argument and u can access the parent class' variable url over here
IAuthenticationProvider mAuthenticationProvider = new IAuthenticationProvider() {
#Override
public void authenticateRequest(final IHttpRequest request) {
request.addHeader("Authorization",
"Bearer " + asToken);
}
};
final IClientConfig mClientConfig = DefaultClientConfig
.createWithAuthenticationProvider(mAuthenticationProvider);
final IGraphServiceClient graphClient = new GraphServiceClient.Builder()
.fromConfig(mClientConfig)
.buildClient();
try {
graphClient.getMe().buildRequest().delete();
} catch (Exception e) {
Log.d(AccountSettingFragment.class.toString(), "Error deleting user. Error Details: " + e.getStackTrace());
}
return true;
}
Currently, my app fails when trying to get an access token with a null pointer exception:
com.microsoft.identity.client.exception.MsalClientException: Attempt to invoke virtual method 'long java.lang.Long.longValue()' on a null object reference
Any idea what I need to do to provide the user the option to users to delete their own account? Thank you!
Thanks for the help, #allen-wu. Due to his help, this azure feedback request and this azure doc, I was able to figure out how to get and delete users silently (without needing intervention).
As #allen-wu stated, you cannot have a user delete itself. So, I decided to have the mobile app call my server-side NodeJS API when the user clicks the 'Delete Account' button (as I do not want to store the client secret in the android app) and have the NodeJS API call the Azure AD endpoint to delete the user silently. The one caveat is that admin consent is needed the first time you try to auth. Also, I have only tested this for Graph API. I'm not a 100% sure if it works for other APIs as well.
Here are the steps:
Create your application in your AAD B2C tenant. Create a client secret and give it the following API permissions: Directory.ReadWrite.All ;
AuditLog.Read.All (I'm not a 100% sure if we need the AuditLog permission. I haven't tested without it yet).
In a browser, paste the following link:
GET https://login.microsoftonline.com/{tenant}/adminconsent?
client_id=6731de76-14a6-49ae-97bc-6eba6914391e
&state=12345
&redirect_uri=http://localhost/myapp/permissions
Login using an existing admin account and provide the consent to the app.
Once you've given admin consent, you do not have to repeat steps 1-3 again. Next, make the following call to get an access token:
POST https://login.microsoftonline.com/{B2c_tenant_name}.onmicrosoft.com/oauth2/v2.0/token
In the body, include your client_id, client_secret, grant_type (the value for which should be client_credentials) and scope (value should be 'https://graph.microsoft.com/.default')
Finally, you can call the Graph API to manage your users, including deleting them:
DELETE https://graph.microsoft.com/v1.0/users/{upn}
Don't forget to include the access token in the header. I noticed that in Postman, the graph api had a bug and returned an error if I include the word 'Bearer' at the start of the Authorization header. Try without it and it works. I haven't tried it in my NodeJS API yet, so, can't comment on it so far.
#allen-wu also suggested using the ROPC flow, which I have not tried yet, so, cannot compare the two approaches.
I hope this helps!
There is a line of code: graphClient.getUsers("").buildRequest().delete();
It seems that you didn't put the user object id in it.
However, we can ignore this problem because Microsoft Graph doesn't allow a user to delete itself.
Here is the error when I try to do it.
{
"error": {
"code": "Request_BadRequest",
"message": "The principal performing this request cannot delete itself.",
"innerError": {
"request-id": "8f44118f-0e49-431f-a0a0-80bdd954a7f0",
"date": "2020-06-04T06:41:14"
}
}
}

Authenticating a REST API with Cognito using AWS Amplify & Android

I am currently trying to configure a REST API I added using AWS Amplify. I have already configured user authentication in which users can sign-up and sign-in by following the steps outlined in the authentication docs. I then added a REST API using the api steps.
At the moment, I am just trying to retrieve a list of items from DynamoDB. The api is successful when I test it on the aws console, however, when I make the call from my android api, it returns the following error:
{"message":"Authorization header requires 'Credential' parameter. Authorization header requires 'Signature' parameter. Authorization header requires 'SignedHeaders' parameter. Authorization header requires existence of either a 'X-Amz-Date' or a 'Date' header. Authorization=[a long string of characters]
I understand that amplify automatically sets the API to be restricted using AWS_IAM, which I think is why the above message is returned. I am trying to get it to authenticate using the user pools I setup before with the authentication steps. The code in my android that app that makes the call to the API is as follows:
RestOptions options = new RestOptions("/models");
Amplify.API.get("modelsapi", options, new ResultListener<RestResponse>() {
#Override
public void onResult(RestResponse restResponse) {
Log.i(TAG, restResponse.toString());
Log.i(TAG, restResponse.getData().asString());
}
#Override
public void onError(Throwable throwable) {
Log.e(TAG, throwable.toString());
}
});
Do I need to setup a Authorizer on AWS api console? And if so, How do I pass the authorization header with the user token. I have a seen a few responses from people using react native but not with android: AWS-amplify Including the cognito Authorization header in the request
The function which the Api invokes is as follows if needed:
app.get(path, function(req, res) {
let queryParams = {
TableName: tableName
}
dynamodb.scan(queryParams, (err, data) => {
if (err) {
res.statusCode = 500;
res.json({error: 'Could not load items: ' + err});
} else {
res.json(data.Items);
}
});
});
Any points/help would be greatly appreciated! Thanks!
Have figured it out. Even though Amplify is meant to take the credentials automatically when making an API call, it seemed to throw up the unauthorized error anyway. When I tested using the console it worked fine. I had to manually add the authorization header to the Rest options:
RestOptions options = RestOptions.builder()
.addPath("models")
.addHeader("Authorization", token.getTokenString())
.build();

Can Firebase work on a Servlet?

I am trying to use Firebase Admin on a Servlet that is communicating on App Engine (Google Cloud Platform). I am using a Servlet because I need to generate a Token towards to validate my access to another API that I am using.
Did anyone have this successful history using Firebase on a Servlet?
I am using com.google.firebase:firebase-admin:5.2.0
App Engine SDK
com.google.appengine:appengine-java-sdk:1.9.50
com.google.appengine:appengine-api-1.0-sdk:1.9.54
Inside the GET I am taking the Token to access the Merchant API.
String mToken = gateway.clientToken().generate();
JSONObject jsonObject = new JSONObject();
jsonObject.put("nonce", mToken);
resp.getWriter().println(jsonObject.toString());
Inside the POST Firebase Admin Full Privileges.
All firebase is inside of a single try and the Transaction Request is in another try.
FileInputStream serviceAccount = new FileInputStream("/WEB-INF/...json");
FirebaseOptions options = new FirebaseOptions.Builder()
.setCredential(FirebaseCredentials.fromCertificate(serviceAccount))
.setDatabaseUrl("https://MyProject.firebaseio.com/")
.build();
FirebaseApp.initializeApp(options);
IAM already grant the read permission.
Firebase Database Reference with the Transaction
DatabaseReference ref = FirebaseDatabase
.getInstance()
.getReference("price");
ref.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
String res = (String) dataSnapshot.getValue();
try {
TransactionRequest request = new TransactionRequest()
.amount(new BigDecimal(res)) //Res doesn't show any error but it also doesn't work
.paymentMethodNonce(nonce)
.options()
.submitForSettlement(true)
.storeInVaultOnSuccess(true)
.done();
Result<Transaction> result = gateway.transaction().sale(request);
Thanks.
Firebase Java Admin SDK often gets used inside servlets. You will need to use a manually scaled instance to deploy on App Engine. Firebase database client starts long running threads, and hence cannot operate on the auto-scaled instances (the new GAE java8 runtime seems more lenient in this regard, but I cannot confirm that right now).
I would recommend you to call FirebaseApp.initializeApp() only once per app, ideally inside a ServletContextListener. Then in your servlet, you should be able to perform your transaction as you do now.

Azure Easy Apis InvokeApi Method is calling GET instead of POST

I am currently working on creating a custom authentication for a Xamarin.Android app using Azure. I have successfully created my API and it is properly returning values when submitting a raw payload using Advanced REST Client.
I am now trying to implement this on Xamarin.Android using Azure's MobileServiceClient SDK and when using the invokeApi method as demonstrated below in my code, I am getting an exception indicating that it is calling GET instead of POST. Is anyone aware of what I might be doing wrong?
ex.Message returns
"Cannot GET /api/register?username=azureAccountTest&password=testingpassword"
public async Task RegisterAsync()
{
Dictionary<string, string> user = new Dictionary<string, string>
{
{ "username", username },
{ "password", password }
};
try
{
CancellationToken ct;
var result = await client.InvokeApiAsync("register", HttpMethod.Post, user, ct);
}
catch(Exception ex)
{
var message = ex.Message;
}
}
According to your description, I tested this issue on my local side and I could retrieve the authenticationToken as follows:
You used the following method for InvokeApiAsync:
public Task<JToken> InvokeApiAsync(string apiName, HttpMethod method, IDictionary<string, string> parameters, CancellationToken cancellationToken = default(CancellationToken));
Note: It summarizes that the Additional data will sent to through the query string.
Per my understanding, you could refer to the following method for sending additional data though the HTTP content as follows:
JObject user = new JObject();
user.Add("username", "bruce");
user.Add("password", "123456");
var result = await App.MobileService.InvokeApiAsync("/.auth/login/custom", HttpMethod.Post, user, ct);
Additionally, you need to specific the mobileAppUri with https endpoint when deploy to azure side. Here is a similar issue, you could refer to here. Moreover, I would recommend you refer to adrian hall's book about Custom Authentication.
UPDATE:
Based on your comment, I checked the custom authentication and found the following note from adrian hall's book about Custom Authentication:
You must turn on Authentication / Authorization in your App Service. Set the Action to take when request is not authenticated to Allow Request (no action) and do not configure any of the supported authentication providers.

Authenticate android app to call web api service

I have an android app that have a login form for student, and I want to check the student credential at web api depending on the stored data in sql server
I have searched the web and watch many videos that talking about many scenarios and nothing helped me.
All I want is a custom validation for my rest service (so I should send the credential for each request)
What should I do at asp.net web api service
how I can implement that at android application
Seems you didn't search for "Web API Token Based Authentication" ;) Anyhow what you need to implement is very simple.
You need to use OAuth 2.0 Resource Owner Credentials Flow which means that you want to provide the username/password only once for a specific endpoint i.e(/token) and then you if the username/password valid you obtain something called Bearer Access Token.
This token is valid for specified period and you can configure this in your Web API.
Once you obtain the access token, you need to store it securely in your android app, then you keep sending it with each request to your web api protected end points using the Authorization header (Bearer scheme(.
I've written very detailed post which covers your scenario 100%. Please check the post Token Based Authentication and let me know if you need further help.
I have used basic authentication for security,so I should provide the base64 encoding of
username:password
in header for each request as the following
authorization: Basic 'encoded username:password
httpGet.setHeader("Authorization", "Basic "+encodeUsernameAndPassword());
At the server side I have implemented message handler
public class BasicAuthenticationHandler : DelegatingHandler
{
public readonly IAuthenticationService authService;
public BasicAuthenticationHandler(IAuthenticationService service)
{
this.authService = service;
}
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
AuthenticationHeaderValue authHeader = request.Headers.Authorization;
if (authHeader == null || authHeader.Scheme != "Basic")
{
return Unauthorized(request);
}
string encodedCredentials = authHeader.Parameter;
var credentialsBytes = Convert.FromBase64String(encodedCredentials);
var credentials = Encoding.ASCII.GetString(credentialsBytes).Split(':');
if (!authService.Authenticate(credentials[0], credentials[1]))
{
return Unauthorized(request);
}
string[] roles = null;//todo
IIdentity identity = new GenericIdentity(credentials[0], "Basic");
IPrincipal user = new GenericPrincipal(identity, roles);
HttpContext.Current.User = user;
return base.SendAsync(request, cancellationToken);
}

Categories

Resources