I have a Xamarin Forms application that is targeting Windows UWP. I have successfully setup Offline Sync and Authentication by following the Microsoft docs such as this article: https://learn.microsoft.com/en-us/azure/app-service-mobile/app-service-mobile-windows-store-dotnet-get-started-users
I have also successfully setup a background (out-of-process) task to run using a Windows Universal Runtime Component.
The process flows as:
1) User runs the application for the first time, they must login and authenticate to Active Directory. The application then caches their token and registers the background task.
2) The background task kicks off on a Timer. During testing, I did NOT have it refreshing the token because I wanted to test the 1-hour token expiration and refresh process.
In my testing, I discovered two things that I am not completely understanding and which I found odd (not behaving as I expected).
1) When I examine the expiration date of the token the user receives upon first login, the expiration date is set for 30 days in the future. I thought it was supposed to expire after 1 hour. Why does it show 30 day expiration date? (This isn't too big of a concern as I did confirm that it does stop allowing access after an hour, just an oddity that I am observing).
2) This is the one I have a concern about. Even though the background task was not able to authenticate after the 1-hour period, it still was able to pull data from Azure to the device. The push data sync failed because authentication failed, but the pull data sync succeeded. This is concerning because I do not want unauthorized attempts to be able to pull data. Has anyone else ran into this? Is this a bug? Did I configure authentication incorrectly somehow?
My Settings:
Azure App Service > Easy Tables (Node.js backend) has all permissions set to "Authenticated Access only".
Azure App Service > Settings > Authentication/Authorization >
App Service Authentication is set to On,
Action to take when request is not authenticated is set to Log in with Azure Active Directory,
Authentication Providers is set Configured for Azure Active Directory.
Mobile App Code:
MobileServiceClient client;
IMobileServiceSyncTable<TableToPull> tableToPullDataFrom;
IMobileServiceSyncTable<TableToPush> tableToPushDataTo;
this.client = new MobileServiceClient(Constants.ApplicationURL);
this.client.CurrentUser = new MobileServiceUser(Settings.UserId);
this.client.CurrentUser.MobileServiceAuthenticationToken = Settings.AuthToken;
store.DefineTable<TableToPull>();
store.DefineTable<TableToPush>();
The Push Async Code is (which fails when authentication fails, as expected):
await this.client.SyncContext.PushAsync();
The Pull Async Code, which should fail when authentication fails but did not (this is my concern) is:
await this.tableToPullDataFrom.PullAsync("tableQuery",this.tableToPullDataFrom.CreateQuery());
I am concerned that the background task was able to pull data from Azure even though authentication failed. I am hopeful that I am misunderstanding this concept in some way and someone can explain to me why this happens? Or if I need to configure something differently? I need to make sure unauthorized logins cannot pull data.
The background task attempts to push and pull data in sequence and I can see that it fails due to invalid authentication during the push task but then succeeds during the pull task. I can also verify this because the pull task does grab updated data from the SQL Azure DB (I can view it using Isolated Storage Explorer and SQLite Browser) but it doesn't send changed data to the SQL Azure DB (viewed in SSMS).
The "action to take when authentication fails" is wrong. You need to set it to "No action". This is so that the authentication can be handled by your code.
If you are using Easy Tables, adjust the permissions on the table to "Authenticated". If you are using ASP.NET, add the [Authorize] attribute to your class.
Authentication is covered in depth in my book - chapter 2 of http://aka.ms/zumobook.
Related
I want to use the gmail api to update myself about the status of a programm I'm running locally 24/7. Basicly once a day it should send me a status report per email from the emailaccount I created just for this case to the same account.
I've got a project set up, the api enabled, got my credentials and created a token.json file. I managed to have it send me emails yada yada yada.
I concentrated on the further development of the programm for some time and then wanted to jump back to this to test out another feature where I wanted to implement a ping me feature. I'd send myself an email asking for a ping back just to check if my program is still running.
While doing that I noticed that my token expired. I tried reading into what I can do about that. Ideally I'd like to have the program just run autonomously. I read for my case that a service account would be ideal but after setting that all up and 2 hours later after a lot of errors I read that interacting with the gmail api with a service account is only open to workspace users since I can't delegate domain-wide authority without one.
So after some further reading I read that next to the access token I created I can refresh that token with refresh tokens. for that I was trying the request function noted in the quickstart tutorial:
if os.path.exists('token.json'):
creds = Credentials.from_authorized_user_file('token.json', SCOPES)
if not creds or not creds.valid:
if creds and creds.expired and creds.refresh_token:
creds.refresh(Request())
now running creds.refresh(Request())
I get this error:
google.auth.exceptions.RefreshError: ('invalid_grant: Token has been expired or revoked.', {'error': 'invalid_grant', 'error_description': 'Token has been expired or revoked.'})
Upon further reading here I read that refesh tokens are only available to projects whose status is set to in progress and not in testing. Projects set to testing are required to have the user manually log in at least once a week which I don't want.
Now for me verifying my project doesn't make sense since I won't have any other users using my access to the gmail api and frankly I wouldn't want that either.
What are my options here to have the script running continuously without having to manually sign in once a week? Considering also that I will be at all times the only user.
Thank you,
Florens
Your still have a few options. For one, you could get a Google Workspace account. The lowest tier would set you back around $6 per user per month. This would allow you to publish the app as internal-only and you don't need to go through the verification process, but you can only use the app with the Workspace account. You can still send emails out to any addresses, though.
If you don't want to pay, you can still set your app to Published status and you do not necessarily have to go through the verification. There are some limitations, such as the app warning that shows up when signing in and a user cap of 100 users, but since you know that the app is safe and you don't need more users you can just ignore this, Google says so in their own documentation:
What app types are not applicable for verification?
Personal Use: The app is not shared with anyone else or will be used by fewer than 100 users. Hence, you can continue using the app by bypassing the unverified app warning during sign-in.
As you already know, the refresh token expires in 7 days only when the app status is set to "testing", so as long as you have it set as "In production" and ignore the unverified app warnings, you should be able to have a normal refresh token that you can use without needing to sign in every 7 days.
Just keep in mind that other users could have access to the app but if you're careful to keep your OAuth credentials to yourself that should not be an issue.
Sources:
Unverified apps
OAuth API verification FAQs
OAuth overview
My current setup is like this. The entire project was built using the official docs here - https://identityserver4.readthedocs.io/en/latest/
API Server
Auth Server with local login, google login and github login
Console based c# client
JS based client
MVC based client.
(all of it, as described in the official docs)
Locally, all of them work beautifully. Able to login, access api endpoints, logout, redirect, the whole thing works smooth.
I have deployed all 5 of them to five different azure web apps. They all have the standard xyz.azurewebsites.net domains ready to use. Now, I have run into some problems.
the console C# client is able to talk to the deployed auth server, collect token using a local account on the auth server and make calls to the deployed API server. Based on this, I assume that both the api server and the auth server working hand in hand, as they should.
Problem #1 - the JS client keeps saying
'The login is blocked because of CORS Missing Allow Origin '
Problem #2 - the MVC client loads the auth server, and then the auth server gives me this error.
Sorry, there was an error : unauthorized_client
Request Id: 80005c0f-0000-eb00-b63f-84710c7967bb
Note : I have set the CORS policy on the auth server, both these clients, under client definition as follows. I am not too concerned about keeping the auth server open, so dont mind if any and every domain can call the auth server.
AllowedCorsOrigins = { "*.*" },
Also Note : I have set the URLS in the code before deployment. all loclahost:port number lines have been replaced correctly with the corresponding now published URLs.
So, what am I missing out here?
Update 1
I was able to solve the CORS issue. Have posted a answer here on another question.
Not able to enable CORS for identity server 4 in asp.net core
Update 2
So, now, both the JS client and the MVC client, are giving identical errors.
Sorry, there was an error : unauthorized_client
Request Id: 80005c0f-0000-eb00-b63f-84710c7967bb
Update 3
I have opened an issue which has log details.
https://github.com/IdentityServer/IdentityServer4/issues/4691
I am not sure if this counts as an answer, but posting for my own question, as it might might help others. Also, this is only a guess at this point.
I found out that the redirects were permanently stored in the database I used with EF migrations. That mean, local in memory redirects were being overwritten anyway by the database stored migrations. I believe this is the issue.
I also realized that the console app is working fine for it does not depend on redirect URLs where as the JS and MVC based clients dont work because they do depend on redirect URLs.
At this point, the best thing to do and for you (if you used EF migrations to store your auth server configuration) on database would be start over and switch to in memory only. Alternatively, you can try and update the database to suit your deployment requirements.
Ultimately, I believe, unless it is absolutely necessary, keep the auth server config (like redirects and CORS settings) in memory as they dont take up much value and are rarely changed.
I am encountering a strange situation with MobileFirst 7.1 where users are occasionally unable to authenticate/login. The only indication that something is awry is a message in the console.log
[AUDIT ] CWWKS1100A: Authentication did not succeed for user ID . An invalid user ID or password was specified.
My custom login module uses com.worklight.core.auth.ext.LdapLoginModule (so to clarify I have a login module which authenticates using LDAP). Like I say everything seems to work most of the time but occasionally users end up in a situation where they are unable to authenticate. I suspect that it is probably related to the session in some way, but that is only a guess based on my investigation.
I have added some logging to my 'secret' adapter which prints the session state to the console log, and obviously this appears in the logs just before the failed authentication message above, but it is empty ie. the session contains nothing.The user is obviously trying to access a secure adapter at this point, and because they are not authenticated they end up at the login page (form based authentication I should say also).
Anyway, I noticed that although there appears to be no session data, the jsessionid is there and has not changed i.e. it does not change even if I refresh the browser. This may not be an issue in itself of course, but interestingly if I remove this entry and refresh my browser I am able to login successfully.
I am pretty sure that my handler code calls the relevant success/failure methods in the correct places but of course there is nothing to stop the user refreshing their browser, which causes them to be re-directed to the login page (the app has been developed using AngularJS so is effectively a single-page navigation model).
The only reproducible test I have been able to come up with is when I login to the MobileFirst console and then try to login to our MF 'desktopbrowser' app. I have read that this situation causes a session-related conflict, but as I say the occasional issue I am seeing is not caused by this (though it may be related).
So the problem seems to have been more related to the flow of logic in our application after successfully logging in, than any inherent issue with the MF Platform.
For example when a user refreshes the browser they are effectively still logged in, but because the app (based on logic we have developed) takes the user to the login page on refresh, the user is effectively re-logging in to the same session. If this failed every time it would of course have been easier to pinpoint but it does not. The solution was to force logout on refresh (when the app initialises), thus cleaning up any session data. In future iterations it may of course be better to re-establish the application based on the authenticated session after refresh, but at present that was a step too far.
Another example of this was post login if the subsequent adapter calls failed (e.g. we authenticate and then retrieve profile data from a database), then we were also not logging the successfully authenticated user out.
We are trying to build OAuth2 Authorization with IdentityServer3.
So we downloaded the Bytes from nuget and connected it with our database.
The database was initialized with the default scopes and the sample clients from Thinktecture self.
Then we connected AD FS as IDP via OWIN and made an simple ExternalUserService.
So far everything worked fine and the permissions page of the IdSrv could be opened, showing the username and that no application has consent up to now.
Then we tried to connect Xamarin.Auth to that and got an error Cannot determine application to sign in to and in the logs an error Signin Id not present (after logon at the ADFS IDP).
To reduce complexity, we decided to go back to the InMemoryUserService and created one InMemoryUser. This worked for the permissions page (at least for a short period of time - time is over now), but it did not allow OAuth2 Authorization Code Flow, which ended up in showing the login page again and again and again. And there is no evidence of any error in the logs.
How can we debug, what is happening? Is there any way to see, why a user gets redirected to the login page again despite being logged in?
--
We reduced the complexity even further by creating a new empty MVC application, which just uses a simple InMemoryUserFactory.
Now it's getting a little bit confusing: one user was able to logon from his machine - other machines (same user - since we created only one) are not able to login and get prompted with the login over and over again.
If using IdentityServer3 and you use own external login methods you should really pay close attention to the API of the IdSrv3.
We tried to create a login resutl with just the subject - this is made for local login on the server. If this is switched off at the same time, you will end up having problems.
So if you use an own external login provider and switch off local login, make sure to call the right overload for the authenticate method (3 Parameters in our case).
My problem is as follows :
I have an application protected by a mobile security test involving a LDAP server. The corresponding realm is called LDAPrealm. I use the form-based authenticator + custom LDAP login module.
When the connection to the worklight server is lost and then re-established, I see that the current user is not authenticated in the LDAP realm anymore.
What I want is be able to re authenticate the user without having him enter credentials again.
However, since the user is still authenticated for other realms included by default in the mobile security test, the worklight server does not challenge the client again for credentials, which is causing j_security_check error when trying to submit credentials.
As a side note those credentials are stored in the encrypted json store for offline authentication and use of the app.
So my question is :
Is it possible to force the server to challenge the client again for this LDAPrealm and use submitLoginForm to re-log in?
More generally, is there a way to clear a user+device from all realms before trying to log in again?
Edit reasons : previous error was caused by a typo
In the case where the user first logs in online then loses connection then get connection again, calling
WL.Client.logout("LDAPRealm",{onSuccess:stealthed_relog});
and calling WL.Client.connect() later in stealthed_relog before sending credentials seems to wield the desired behaviour.
However, when the user logs in offline and then gets connection, when I try to use WL.Client.connect(), it says another instance of WL.Client.connect has already been called.
edit : for the log offline case, the application get challenged automatically shortly after that the connected event fires (cause of heartbeat? I do not really know), so you just have to use
login_clientside.submitLoginForm();
to successfully log in again.
If someone has a better way to implement auto-reconnecting in worklight with ldap server, feel free to post it and I'll unaccept my answer.