Hi everyone,
... I'd like to make a suggestion to improve the security mechanics in
Fineract. For the impatient first a...
TL;DR:
current security in Fineract: inflexible, liability, maintenance eating
into our time budget, increasing number of CVEs expected
vs
third party OAuth integration: outsource all security related
maintenance to another dedicated team/community (e. g. Keycloak), more
robust implementation, more features (password hash functions, advanced
user interfaces, 100% standard conform workflows), zero technical debt
for Fineract, flexibility (LDAP, Active Directory, Social Media logins
aka no passwords stored on our system)
What we currently have is a straight forward implementation of role
based access control (RBAC) using a relational database for storage.
This implementation served us well in the past, but I think it's
becoming a bit inflexible for integration in bigger enterprise
architectures (read: LDAP/Active Directory, SSO...). Our default
authentication scheme is still Basic Auth which - I think is safe to say
- is not secure and absolutely not recommended for production. To
address this issue we added an OAuth module and a 2FA module. Even those
improvements start to have their own issues; e. g. our OAuth
implementation is based on an Apache sister project called Oltu...
which is unfortunately retired (read: end of life). We are even not able
to use the latest 1.0.2 version, because it's incompatible with some of
the other dependencies we have (I don't remember exactly, but it was
probably related to OpenAPI).
What I want to say is: I think in the long run we cannot win this race
for up to date security and flexibility when integrating Fineract in 3rd
party environments with existing security infrastructure. We are
responsible for every piece of code we ship - and this includes all
security related parts of course. I'm confident that our community would
be capable to address any bugs or improvements around security, but we
have to ask ourselves if "security" is what we do or if it's "finance".
Don't get me wrong, of course Fineract needs to be secured... but my
point is: are we the best to do it on top of everything else we do or
can we delegate this to someone else and invest our time in and focus on
improving Fineract's core features?
I think that OAuth in particular is going to stay for a (long) while as
the common denominator for everything concerning authentication, so...
why not make this our default authentication scheme and ditch Basic Auth
for good (why keep it when it's just potentially creating security
concerns). Let's ignore for a moment the impact (read: code changes)
such a decision would have and let's think for a moment how we could
integrate such a feature in Fineract with minimal effort from our side
and what benefit this would bring to the community.
Spring Boot and Spring Security overhauled their OAuth integrations
fairly recently. For a while this was a bit confusing. There were two
competing OAuth implementations available and it was not really clear
which one was the preferred way to use (at least not to me).
There is a really simple way to get you going with OAuth authentication
now ("OAuth client configuration"). I won't go into the details, but the
new Spring Security libraries are supporting auto configuration and
other Spring Boot conventions extensively and make the adjustments
really trivial. Just a handful of entries in application.properties and
you are pretty much done... if you use existing services (social media
logins like Google, Facebook, Twitter...) and/or an existing OAuth
identity server.
There is a - kind of - identity server product available from Spring
(https://spring.io/projects/spring-authorization-server); actually it's
more like an embedded library that turns a Spring Boot instance into an
OAuth server. This library offers everything you'd need to support the
OAuth standard, but it's a minimal implementation. There is no user
interface and the features cover the bare minimum you need to meet the
OAuth requirements. And this solution requires at least some coding.
Instead of Spring's Authorization server I'd suggest to use Keycloak
(https://keycloak.io). For those who don't know it: Keycloak is an
open-source identity and access management solution that provides set of
features for authentication and authorization. It has a robust security
model with support for multiple authentication protocols, including
OAuth 2.0 and OpenID Connect. Integrating with Keycloak allows you to
take advantage of these protocols without having to implement them yourself.
Keycloak would allow us to keep a similar centralized user management
(supports various relational databases) with an advanced web UI (for
configuration and user management)... if we really would want to keep
the user data actually. We can also configure it to use other SSO/Social
Media authentication providers which would relieve us from saving highly
sensitive data in our databases: passwords. If we don't store it then we
can't lose it.
Other features we get with Keycloak basically for free:
- we get proper 2FA for free (really works well with apps like Authy)
- proper password resets
- secure password policies
Keycloak has a very active community that produces frequent
releases/updates. We could benefit hugely from their ongoing development
and maintenance. We could also tap into their security domain related
knowledge pool.
We could integrate Keycloak relatively easily (please take this as a
placeholder; I think Keycloak would be a very good choice, but maybe
there are other/better OS projects out there).
Before we do anything I would suggest to analyze our current security
mechanics and try to extract them as a separate (custom) module with
100% backwards compatibility.
Once this is working we would create another (custom) module to make
Keycloak a drop-in replacement for the legacy security mechanics.
To get the authentication part in place you are pretty much done with 3
line of configuration in application.properties. Unfortunately we use
the implementation of our homegrown security solution quite a bit in the
code base. There are the classes AppUser and PlatformUserDetailsService
that are pretty much directly tied to a relational databases. Especially
AppUser is actually a JPA entity class and embedded/used in other entity
classes (see Loan...). To avoid major refactorings we would need to
create a bit of glue code that creates entries in the AppUser table with
metadata taken from OAuth access tokens (I'm pretty sure that Spring
Security OAuth fires internally some events that we can tap into and use
to fill in missing data). Again: we would maintain AppUser only and fill
it's database table to keep things working.
Concerning authorization I could imagine that we need to do a bit more
work. Again, we can figure this out later. I think it's possible to
achieve this even without any reliance on legacy role tables etc.
Technically this integration is pure OAuth and nothing Keycloak specific
on our side... makes configuration of a different OAuth compliant
identity server a minor effort... and involves usually no coding.
Please add your comments and questions... there is also a Jira ticket
with a bit more information
(https://issues.apache.org/jira/browse/FINERACT-1908).
Cheers,
Aleks