[
https://issues.apache.org/jira/browse/DERBY-866?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=13223333#comment-13223333
]
Rick Hillegas commented on DERBY-866:
-------------------------------------
At this point, I am declaring victory on the coding/unit-testing of NATIVE
authentication. I believe that I have implemented and verified all of the
functionality in the spec. I have reached the end of my ability to test this
feature productively. My blinders, as the author of this feature, prevent me
from discovering additional defects. The tests I have written lately do
disclose defects in other parts of Derby outside the scope of this feature--but
not new defects in NATIVE authentication itself.
However, I'm sure there are plenty of remaining defects, perhaps even some real
howlers. At this point, buddy-testers may be able to find some of the defects
hidden behind my blinders.
To help buddy-testers guess where the weaknesses lie, I would like to describe
the current implementation and its touchpoints with other parts of Derby.
--------------------------------------------------
-- NATIVE Authentication Service
--------------------------------------------------
The core of the implementation is the NATIVE authentication service itself,
NativeAuthenticationServiceImpl. This implementation is parallel to the other
authentication services, and like them, it extends AuthenticationServiceBase:
1) BasicAuthenticationServiceImpl - This class implements BASIC authentication.
I used it as the template for NativeAuthenticationServiceImpl because NATIVE
and BASIC authentication share a key trickiness: the storing of credentials
inside the database being connected to.
2) JNDIAuthenticationServiceImpl - This class handles LDAP authentication.
3) SpecificAuthenticationServiceImpl - This class handles user-written
authenticators.
4) NoneAuthenticationServiceImpl - This is the default, NOP authentication
service used when the application does not require any authentication at all.
At engine and database startup, all of these implementations of the
authentication module are asked whether they match the setting of the Derby
authentication properties. I had to modify SpecificAuthenticationServiceImpl
because it is the catch-all implementation: by default it matches any setting
of derby.authentication.provider which has not been excluded explicitly. There
are quite a few Derby authentication properties:
derby.authentication.builtin.algorithm
derby.authentication.ldap.searchAuthDN
derby.authentication.ldap.searchAuthPW
derby.authentication.ldap.searchBase
derby.authentication.ldap.searchFilter
derby.authentication.provider
derby.authentication.server
derby.connection.requireAuthentication
--- Bootstrapping
The first bit of trickiness in NativeAuthenticationServiceImpl is the logic
which determines whether this implementation matches the setting of the Derby
authentication properties. This is tricky because unlike the other
authentication services, NATIVE authentication is supposed to be easy for the
user to configure. It only requires that you set one property, viz.
derby.authentication.provider. The other authentication services require that
you redundantly set derby.connection.requireAuthentication.
Bootstrapping NATIVE authentication follows the normal Derby model, which
divides bootstrapping into two phases: canSupport() and boot(). Validation of
property settings can't be performed by canSupport() because that method does
not let you raise an invalidation exception. Note that this behavior gives rise
to the quirky result that if you garble the setting of
derby.authentication.provider, you will end up booting the catch-all
SpecificAuthenticationServiceImpl, which will promptly fall over because the
garbled derby.authentication.provider does not resolve to a valid class name.
However, deferring the validation of derby.authentication.provider to
NativeAuthenticationServiceImpl.boot() is fine. That is because the NATIVE
authentication service needs to know whether it is being booted system-wide or
inside a specific database. The value NATIVE::LOCAL is meaningless for
system-wide authentication but it is the only legal value which can be stored
in a database. That last point is true because we don't want to hard-code the
name of the system-wide credentials db inside any specific database; we want
the database to be portable and we want to give the system administrator the
option of moving the credentials db if there is a problem.
--- Creating the credentials DB
The next bit of trickiness involves coupling connection management with NATIVE
authentication. Special logic in EmbedConnection checks to see whether the
database being created is the credentials database. If so, authentication isn't
performed: there is no authentication authority yet and the presented
credentials are simply accepted as is and will be used to create the DBO
account. It might make more sense if this logic were inside
NativeAuthenticationServiceImpl. However, the knowledge that the database is
being created is not passed across the authentication call, so
NativeAuthenticationServiceImpl can't perform this check.
--- Steady-state
The rest of the logic in NativeAuthenticationServiceImpl happens under
authenticateUser() and processes the main execution path: authenticating users
for system-wide or database-specific tasks. At this point the NATIVE
authentication service is booted and we know that we are not authenticating the
creation of the credentials db itself.
The authenticateUser() method figures out whether credentials should be looked
up in the current database or in another database.
Looking up the credentials in another database gives rise to the next bit of
trickiness. This logic has already been corrected to account for a deadlock in
the Java 5 VM. We were doing something which fell outside the main execution
path understood by the VM's JDBC layer, viz., we were trying to open a nested
JDBC connection in the middle of establishing an outer JDBC connection. After
the corrective logic, we are now merely trying to establish a nested Derby
connection while trying to establish an outer Derby connection. Needless to
say, this still falls outside the main execution path understood by Derby and
there may be bugs lurking here.
Other trickiness may lurk inside the logic which looks up credentials in the
current database. To find the real credentials, we must access the Store before
the connection has been completely established. Fortunately, BUILTIN
authentication has been doing this for years so many bugs in this area may have
been flushed out already. We also access the DataDictionary before the
connection has been completely established. This unusual code path is not
exercised by BUILTIN authentication and so it may be hiding some bugs.
--------------------------------------------------
-- Properties Management
--------------------------------------------------
NATIVE authentication attempts to be simple to configure and hard to turn off.
All you have to do is turn one knob (the derby.authentication.provider
property). When you turn this knob to NATIVE authentication, you also turn on
SQL authorization. Once NATIVE authentication has been set in the database
itself, it can't be disabled.
The interaction of Derby properties is already complicated and is influenced by
the following considerations:
o Whether the property is set on the VM command line, in
derby.properties, or in the database.
o Whether the special derby.database.propertiesOnly property is set.
o Whether other, related properties have been set correctly.
I confess to being confused repeatedly by the way that Derby properties
interact. And now I have complicated that interaction by introducing the
peculiar, trumping behaviors of NATIVE authentication. The goal was to simplify
how users protect their data, but I can't promise that edge cases haven't crept
in or been made worse. A crucial piece of trumping happens in
PropertyUtil.getPropertyFromSet(). There could be more bugs in this area as
well.
--------------------------------------------------
-- Data Dictionary
--------------------------------------------------
The Data Dictionary assists NATIVE authentication. Here are the major
touchpoints:
1) A new SYSUSERS catalog has been added. Unlike other catalogs, ordinary users
can't view this catalog (when authentication is on) and even the DBO can't view
the PASSWORD column. These behaviors are unprecedented so they may be
particularly buggy.
2) I added 4 new procedures for managing passwords:
syscs_util.syscs_create_user, syscs_util.syscs_drop_user,
syscs_util.syscs_reset_password, and syscs_util.syscs_modify_password. The
first 3 are modelled on other, existing DBO-only procedures. The last procedure
is modelled on existing procedures which anyone can run.
3) I moved the password-hashing logic into a PasswordHasher class in the Data
Dictionary.
> Derby User Management Enhancements
> ----------------------------------
>
> Key: DERBY-866
> URL: https://issues.apache.org/jira/browse/DERBY-866
> Project: Derby
> Issue Type: Improvement
> Components: Services
> Affects Versions: 10.2.1.6
> Reporter: Francois Orsini
> Assignee: Rick Hillegas
> Attachments: Derby_User_Enhancement.html,
> Derby_User_Enhancement_v1.1.html, DummyAuthenticator.java,
> UserManagement.html, UserManagement.html, UserManagement.html,
> UserManagement.html, UserManagement.html, UserManagement.html,
> derby-866-01-aa-sysusers.diff, derby-866-01-ab-sysusers.diff,
> derby-866-02-ag-createDropUser.diff,
> derby-866-03-aa-resetModifyPassword.diff,
> derby-866-03-ab-resetModifyPassword.diff, derby-866-04-aa-fixRolesTest.diff,
> derby-866-05-aa-grantRevoke.diff, derby-866-06-aa-upgradeFrom10.1.diff,
> derby-866-07-aa-removeSQLPassword.diff, derby-866-08-aa-passwordHasher.diff,
> derby-866-08-ab-passwordHasher.diff, derby-866-08-ad-passwordHasher.diff,
> derby-866-09-ad-nativeAuthenticationService.diff,
> derby-866-09-ae-nativeAuthenticationServiceWithTests.diff,
> derby-866-10-ac-propChanging.diff, derby-866-11-aa-upgradeTest.diff,
> derby-866-12-ac-passwordExpiration.diff,
> derby-866-13-ab-systemWideOperationTests.diff,
> derby-866-14-ac-badNativeSpec.diff,
> derby-866-15-ae-dbInJarFileOrOnClasspath.diff,
> derby-866-16-aa-credDBViaSubprotocol.diff,
> derby-866-17-aa-grantRevokeNative.diff,
> derby-866-18-aa-encryptedCredentialsDB.diff,
> derby-866-19-aa-replicationTest.diff, derby-866-20-aa-npeAndUserProbing.diff,
> derby-866-20-ab-npeAndUserProbing.diff,
> derby-866-21-aa-emptyCredentials.diff, derby-866-21-ab-emptyCredentials.diff,
> dummyCredentials.properties, releaseNote.html
>
>
> Proposal to enhance Derby's Built-In DDL User Management. (See proposal spec
> attached to the JIRA).
> Abstract:
> This feature aims at improving the way BUILT-IN users are managed in Derby by
> providing a more intuitive and familiar DDL interface. Currently (in
> 10.1.2.1), Built-In users can be defined at the system and/or database level.
> Users created at the system level can be defined via JVM or/and Derby system
> properties in the derby.properties file. Built-in users created at the
> database level are defined via a call to a Derby system procedure
> (SYSCS_UTIL.SYSCS_SET_DATABASE_PROPERTY) which sets a database property.
> Defining a user at the system level is very convenient and practical during
> the development phase (EOD) of an application - However, the user's password
> is not encrypted and consequently appears in clear in the derby.properties
> file. Hence, for an application going into production, whether it is embedded
> or not, it is preferable to create users at the database level where the
> password is encrypted.
> There is no real ANSI SQL standard for managing users in SQL but by providing
> a more intuitive and known interface, it will ease Built-In User management
> at the database level as well as Derby's adoption.
--
This message is automatically generated by JIRA.
If you think it was sent incorrectly, please contact your JIRA administrators:
https://issues.apache.org/jira/secure/ContactAdministrators!default.jspa
For more information on JIRA, see: http://www.atlassian.com/software/jira