[ 
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


Reply via email to