Clean architecture and authentication - android

How should authentication be implemented to fit in the Clean Architecture pattern?
Say I need a token (oauth, googleapi, I see you) for some of my API requests. How should I get this token from my login screen and User Repository to my RandomDataRepository for example?
It seems strange to put that in each of my RandomData Use Cases, and strange too to have my remote RandomData layer talking to another Repository module.
Should the token be passed for every request (kinda ugly if my repository can switch from cache / remote), or should it be injected once and referenced somewhere, like in an interceptor?
I found this but I don't understand the login worfklow and there's no full code)
Thanks !

Related

What's a reliable way to persist the current logged in user in a clean android architecture?

I've been searching for a clean, reliable way to persist the current user in an Android app, which is accessible from any activity/view, is available immediately, and can be reliably cleared upon logout.
To add further context, the app handles API authentication via a token (JWT). Unfortunately there is no user info in the payload.
There is an MVVM architecture, and there is a Repository layer, which calls a retrofit api/room db.
Here are the things I'm exploring, would love to know if any are any better ways to go, or if there's another pattern/architecture I've not discovered yet:
Presently a User object is persisted on the Application class. I hate this personally, it's what existed previously. Upon successful login, the JWT is stored in SharedPreferences, and the User object is saved as a static variable in the Application class.
Immediately there is the thought to at least store the important bits of the user in SharedPreferences too. I was trying to find someway to "bundle" the user with the JWT, sharedpreferences doesn't really play nicely with objects though. I imagine a scenario where I may have a stored token for one user, but the User object for another, which will cause all sorts of problems.
As well as our retrofit API service layer, there is a basic Room db spun up as I slowly try to incorporate local caching throughout the app. So I know I can persist the User here, although worried about the async nature of DB calls.
I feel what I'm after is some kind of architectural layer, a SesssionManager or something, that takes care of all of this. Will "hold" the User, the Token, have a global Logout() method, will somehow play nicely with the repository layer, so the View and ViewModels don't really need to bother with the user or userId at all, just make the various repository calls, and the data (repository/retrofit service) layers will return what is right for the currently logged in user etc.
Sorry if this is a bit abstract/high level without any specific code, I just remember finding months ago an excellent article to do with this notion of a Session layer, and didn't bookmark it and now am scratching my head trying to work out the best way to achieve this cleanly.

Clean Architecture and authentication. Correct way?

I'm working on an Android app based on Clean Architecture pattern and I have doubts how to implement user authentication in a clean way. Is the following solution clean in terms of clean architecture?
I would create use cases like below (executed from presentation layer):
LoginUseCase (for provided login and password fetches api token via remote service and saves in local token source)
LogoutUseCase (clears token from LocalTokenSource)
(LocalTokenSource interface would be stored in domain layer and its implementation in data layer - kind of repository)
And in order to perform token refresh at each app launch (it's not a use case from the user perspective, right?) I would create SessionManager component in domain layer. SessionManager would be responsible for refreshing token and saving it in LocalTokenSource. Each time activity is started, from its presenter I would execute refreshToken() on injected SessionManager. What do you think about the solution?
If it's clean, then how to handle passing token to the remote service to execute other API methods which require token? Lets say I have PostsRepository which fetches posts data from remote service. Should I pass token from a use case to the repository method like repo.getPosts(token)? Or inject LocalTokenSource to the repository, so it could read the token on its own? Wouldn't the second option violate Clean Architecture rules, because LocalTokenSource would be used in 2 layers?
The central question you would have to decide is: Do you want to model authorization (and so the usage of the token) as an aspect of your business logic OR do you want to consider it as an "implementation detail".
If you decide for the first, having dedicated use cases for it, adding the SessionManager to the domain layer and passing the token to the repositories would be a consistent modeling.
If you decide for the later, login/logout/refresh as well as the existence of the token is probably best kept "behind the scenes", so in the framework or gateway layer.
Both approaches would follow the rules of the Clean Architecture (as long as you do not violate the dependency rule).

Repository as only communication with Data Layer?

I am following clean architecture, and I understand the use of the repository for actions like getUsers or queryUsers. However does not make sense to me the use of a repository to login a user. How should I communicate with the Data Layer then, should I skip the repository layer and access the network layer?
I definitely think that you should not skip layers.
The whole point of introducing a certain architecture is to follow it without exception, so all your app modules behave in an expected and predictable way.
So, if you look at it from a different angle, what does logging in mean? You get a username and a password and you must check if they match a username and a password that are stored in your datasource. To do this, you run a query against your current users. And queries are run where - in the repository! You said it yourself - the repository is where all querying should happen. What is implementation behind it is of no importance.
So, my suggestion is to add a method like this one:
public interface UserRepository {
User findByUsernameAndPassword(#NonNull String username, #NonNull String
password);
}
If you manage to find a user - good, he's authenticated, if not - sorry, try again.
from this guid i think using repository is a better choice. my answer based on the definition of the repository quoting :
Repository modules are responsible for handling data operations.
I believe in clean architecture you should not skip layers. I see a few options here:
userRepository.get\set-User() - for me, it looks a bit weird because Repository is an abstraction over collection while we need only one.
create an abstraction over user storage. For example, userStorage.get\set-User() or userStorage.login(User), logout(), get()

Networking app architecture

I'm building an android app similar to a facebook app, aimed to display various information stored in a database.
I'm using on the server-side a REST API, which returns responses based on various POST requests, with a facebook token authentification.
And on the client-side, I'm using the volley library to deal with network requests. I've tried numerous possibities but I'm searching for the most elegant way of communicating with the server, and since this is a trivial case, I thought you could maybe help me with this one...
Since I'm always checking fb tokens, and making similar POST requests, I considered adding a Connexion objet, which creates a volley request when prompted with an execute(POST parameters...); method, and calls a callback method when the response has arrived.
But I'm struggling to decide whether I should create a SessionManager object (Singleton or not ?) which can process ALL the data from session related responses (like check login, login...) based maybe on codes (for example Error 5xx for every type of response), and DO the intents.
Or I should process these responses in every activity, and do the intents there. Knowing they can maybe repetitive.
In short, I'm looking for a best practice to apply when the app has to process common responses, and not so uncommon responses for example.
Keep all the logic in the activities ? Create objects ?
Don't hesitate to post your opinion on the subject !
Thank you very much.
EDIT : Ended up using a Connexion object to process all the requests (with volley). As for the Intents, I kept all that logic in the activities and haven't used another controller. The result was not ugly. Mainly because I used a secondary route which does the authentification, so the server ALWAYS responds with a big error if you're an evil hacker.
First of all I am not working with Volley but with the Apache HttpClient, this should not matter for your question though.
Having the code which handles the Post Requests in your Activities is a bad solution. See:
Single Responsibility Principle
Your idea with creating a SessionManager is really good though. You can handle all the stuff in the SessionManager and not bother with it in your Activities. Additionally you should add classes for different purposes than managing the session. If you get all friends from a specific user you should create a FriendsController or FriendsManager.
Processing the answers can be done in a single class too. I assume that you receive JSON from your API as response. Create one class that takes the response and returns a JSONObject.
Although it is far from perfect feel free to take a look at my app. I am currently learning Android / Java so it might not be as perfect as one might expect. The classes to handle POSTs are called YYYController and not Manager. But this is just a naming convention I use:
My Android Project
Your calls can return an enum in which you store the different Callback types:
class Enum Callbacks {
SUCCESS,
CREATED,
UNPROCESSABLE_ENTITY
}
In your application you can use them like this:
Callbacks response = SessionManager.login();
if (response == Callbacks.SUCCESS) {
//your login logic here
}

Android: Some questions about security and user authentication (register, login) through HTTP

I just can't get my head straight about this one. I'm currently building a rather large-scale application on Android. I've run in to a couple of problems regarding security and authentication though...
The Scenario:
I have an application that's making calls through HTTP (will implement SSL later) to a server running PHP and MySQL. Of course i want to use the existing user-database, so migration to another DB is not a solution..
I've managed to create the "register users via Android to the server"-functionality.
I've also made a working login, BUT this is where the problems start.
As users in the Android application I'am working on adds, edits, deletes and sync stuff on the server via/to the application, things get rather complicated. A little too complicated for me it seems :)
Problems:
As I get the result from my server-side login and pass it from the
server to Android via JSON, the connection dies and server-side I
'aint logged-on (sessions dies) whereas on the phone I'am. How can I
make the log-on persistent both on the server and in Android without
the need to log-on again? So that subsequent calls from Android to
the server is made with the same user, still authenticated. I.e. I
want sort of a one-time login ('till I logout) like in the
Spotify-app (and many others).
If I've understood things right, implementing SSL correct makes it
possible to send passwords in clear text to the server without the need to hash them first. Is this correct?
I just can't stop thinking about the fact that a MIM-attack would compromise any unique id I send from Android to the server. My first thought was to have the UID on the Android device as a "key" to the server after a successful log-on. But if that key gets in the wrong hands, the user associated with that UID will be compromised. I've looked at the AccountManager on Android but it seems rather over-kill in my case.
If someone could supply examples or at least guidelines, I'd be much grateful!
Thanks in advace!
ADDED SOLUTION DIAGRAM AFTER EDIT
Notice that this diagram shows the first start of the application. Later startups will NOT show the Login / Register form, but use the DUT instead.
// Alexander
Issue some form of a short-lived authentication token to Android apps. They would need to pass it in every request, and you will check it your Web app. Breaking the connection doesn't end the session, if it does, you have bug in your Web app: fix it. In Android, as long as you are using the same HttpClient instance, it will continue to use the same session, nothing special is needed.
Whatever you do, do not put off implementing SSL, do it now.

Categories

Resources