1
/*******************************************************************************
2
*Copyright (c) 2009 Eucalyptus Systems, Inc.
4
* This program is free software: you can redistribute it and/or modify
5
* it under the terms of the GNU General Public License as published by
6
* the Free Software Foundation, only version 3 of the License.
9
* This file is distributed in the hope that it will be useful, but WITHOUT
10
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14
* You should have received a copy of the GNU General Public License along
15
* with this program. If not, see <http://www.gnu.org/licenses/>.
17
* Please contact Eucalyptus Systems, Inc., 130 Castilian
18
* Dr., Goleta, CA 93101 USA or visit <http://www.eucalyptus.com/licenses/>
19
* if you need additional information or have any questions.
21
* This file may incorporate work covered under the following copyright and
24
* Software License Agreement (BSD License)
26
* Copyright (c) 2008, Regents of the University of California
27
* All rights reserved.
29
* Redistribution and use of this software in source and binary forms, with
30
* or without modification, are permitted provided that the following
33
* Redistributions of source code must retain the above copyright notice,
34
* this list of conditions and the following disclaimer.
36
* Redistributions in binary form must reproduce the above copyright
37
* notice, this list of conditions and the following disclaimer in the
38
* documentation and/or other materials provided with the distribution.
40
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
41
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
42
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
43
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
44
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
45
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
46
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
47
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
48
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
49
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
50
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. USERS OF
51
* THIS SOFTWARE ACKNOWLEDGE THE POSSIBLE PRESENCE OF OTHER OPEN SOURCE
52
* LICENSED MATERIAL, COPYRIGHTED MATERIAL OR PATENTED MATERIAL IN THIS
53
* SOFTWARE, AND IF ANY SUCH MATERIAL IS DISCOVERED THE PARTY DISCOVERING
54
* IT MAY INFORM DR. RICH WOLSKI AT THE UNIVERSITY OF CALIFORNIA, SANTA
55
* BARBARA WHO WILL THEN ASCERTAIN THE MOST APPROPRIATE REMEDY, WHICH IN
56
* THE REGENTS’ DISCRETION MAY INCLUDE, WITHOUT LIMITATION, REPLACEMENT
57
* OF THE CODE SO IDENTIFIED, LICENSING OF THE CODE SO IDENTIFIED, OR
58
* WITHDRAWAL OF THE CODE CAPABILITY TO THE EXTENT NEEDED TO COMPLY WITH
59
* ANY SUCH LICENSES OR RIGHTS.
60
*******************************************************************************
61
* Author: chris grzegorczyk <grze@eucalyptus.com>
63
package com.eucalyptus.auth;
65
import java.security.GeneralSecurityException;
66
import java.security.cert.X509Certificate;
67
import java.util.List;
68
import org.apache.log4j.Logger;
69
import org.hibernate.Session;
70
import org.hibernate.criterion.Example;
71
import org.hibernate.criterion.MatchMode;
72
import com.eucalyptus.auth.api.GroupProvider;
73
import com.eucalyptus.auth.api.NoSuchCertificateException;
74
import com.eucalyptus.auth.api.UserInfoProvider;
75
import com.eucalyptus.auth.api.UserProvider;
76
import com.eucalyptus.auth.crypto.Crypto;
77
import com.eucalyptus.auth.crypto.Hmacs;
78
import com.eucalyptus.auth.principal.Group;
79
import com.eucalyptus.auth.principal.User;
80
import com.eucalyptus.auth.util.B64;
81
import com.eucalyptus.auth.util.PEMFiles;
82
import com.eucalyptus.entities.EntityWrapper;
83
import com.eucalyptus.util.EucalyptusCloudException;
84
import com.eucalyptus.util.Tx;
85
import com.google.common.collect.Lists;
87
public class DatabaseAuthProvider implements UserProvider, GroupProvider, UserInfoProvider {
88
private static Logger LOG = Logger.getLogger( DatabaseAuthProvider.class );
90
public DatabaseAuthProvider( ) {}
93
public User addUser( String userName, Boolean isAdmin, Boolean isEnabled ) throws UserExistsException {
94
UserEntity newUser = new UserEntity( userName );
95
newUser.setQueryId( Hmacs.generateQueryId( userName ) );
96
newUser.setSecretKey( Hmacs.generateSecretKey( userName ) );
97
newUser.setAdministrator( isAdmin );
98
newUser.setEnabled( isEnabled );
99
newUser.setPassword( Crypto.generateHashedPassword( userName ) );
100
newUser.setToken( Crypto.generateSessionToken( userName ) );
101
EntityWrapper<UserEntity> db = Authentication.getEntityWrapper( );
105
} catch ( Throwable t ) {
107
throw new UserExistsException( t );
109
EntityWrapper<UserInfo> dbU = EntityWrapper.get( UserInfo.class );
111
String confirmCode = Crypto.generateSessionToken( userName );
112
UserInfo newUserInfo = new UserInfo( userName, confirmCode );
113
dbU.add( newUserInfo );
115
} catch ( Exception e ) {
119
User proxy = new DatabaseWrappedUser( newUser );
120
Groups.DEFAULT.addMember( proxy );
125
public void deleteUser( String userName ) throws NoSuchUserException {
126
UserEntity user = new UserEntity( userName );
127
EntityWrapper<UserInfo> dbU = EntityWrapper.get( UserInfo.class );
129
UserInfo newUserInfo = dbU.getUnique( new UserInfo( userName ) );
130
dbU.delete( newUserInfo );
132
} catch ( Exception e ) {
136
EntityWrapper<User> db = Authentication.getEntityWrapper( );
138
User foundUser = db.getUnique( user );
139
for( Group g : Groups.lookupUserGroups( foundUser ) ) {
140
g.removeMember( foundUser );
142
db.delete( foundUser );
144
} catch ( Exception e ) {
146
throw new NoSuchUserException( e );
151
public List<Group> lookupUserGroups( User user ) {
152
List<Group> userGroups = Lists.newArrayList( );
153
EntityWrapper<GroupEntity> db = Authentication.getEntityWrapper( );
155
UserEntity userInfo = db.recast( UserEntity.class ).getUnique( new UserEntity( user.getName( ) ) );
156
for ( GroupEntity g : db.query( new GroupEntity( ) ) ) {
157
if ( g.isMember( userInfo ) ) {
158
userGroups.add( DatabaseWrappedGroup.newInstance( g ) );
162
} catch ( EucalyptusCloudException e ) {
170
public Group lookupGroup( String groupName ) throws NoSuchGroupException {
171
EntityWrapper<GroupEntity> db = Authentication.getEntityWrapper( );
173
GroupEntity group = db.getUnique( new GroupEntity( groupName ) );
175
return DatabaseWrappedGroup.newInstance( group );
176
} catch ( EucalyptusCloudException e ) {
178
throw new NoSuchGroupException( e );
183
public List<User> listAllUsers( ) {
184
List<User> users = Lists.newArrayList( );
185
EntityWrapper<UserEntity> db = Authentication.getEntityWrapper( );
186
UserEntity searchUser = new UserEntity( );
187
UserEntity user = null;
189
for( UserEntity u : db.query( searchUser ) ) {
190
users.add( new DatabaseWrappedUser( u ) );
193
} catch ( Throwable e ) {
200
public List<User> listEnabledUsers( ) {
201
List<User> users = Lists.newArrayList( );
202
EntityWrapper<UserEntity> db = Authentication.getEntityWrapper( );
203
UserEntity searchUser = new UserEntity( );
204
searchUser.setEnabled( true );
205
UserEntity user = null;
207
for( UserEntity u : db.query( searchUser ) ) {
208
users.add( new DatabaseWrappedUser( u ) );
211
} catch ( Throwable e ) {
218
public User lookupCertificate( X509Certificate cert ) throws NoSuchUserException {
219
String certPem = B64.url.encString( PEMFiles.getBytes( cert ) );
220
UserEntity searchUser = new UserEntity( );
221
searchUser.setEnabled( true );
222
X509Cert searchCert = new X509Cert( );
223
searchCert.setPemCertificate( certPem );
224
searchCert.setRevoked( null );
225
EntityWrapper<UserEntity> db = EntityWrapper.get( searchUser );
226
Session session = db.getSession( );
228
Example qbeUser = Example.create( searchUser ).enableLike( MatchMode.EXACT );
229
Example qbeCert = Example.create( searchCert ).enableLike( MatchMode.EXACT );
230
List<UserEntity> users = ( List<UserEntity> ) session.createCriteria( UserEntity.class ).setCacheable( true ).add( qbeUser ).createCriteria( "certificates" )
231
.setCacheable( true ).add( qbeCert ).list( );
232
UserEntity ret = users.size( ) == 1 ? users.get( 0 ) : null;
233
int size = users.size( );
235
return new DatabaseWrappedUser( ret );
237
throw new GeneralSecurityException( ( size == 0 ) ? "No user with the specified certificate." : "Multiple users with the same certificate." );
239
} catch ( Throwable t ) {
240
throw new NoSuchUserException( t );
247
public boolean checkRevokedCertificate( X509Certificate cert ) throws NoSuchCertificateException {
248
String certPem = B64.url.encString( PEMFiles.getBytes( cert ) );
249
UserEntity searchUser = new UserEntity( );
250
searchUser.setEnabled( true );
251
X509Cert searchCert = new X509Cert( );
252
searchCert.setPemCertificate( certPem );
253
searchCert.setRevoked( true );
254
EntityWrapper<UserEntity> db = EntityWrapper.get( searchUser );
255
Session session = db.getSession( );
257
Example qbeUser = Example.create( searchUser ).enableLike( MatchMode.EXACT );
258
Example qbeCert = Example.create( searchCert ).enableLike( MatchMode.EXACT );
259
List<User> users = ( List<User> ) session.createCriteria( User.class ).setCacheable( true ).add( qbeUser ).createCriteria( "certificates" )
260
.setCacheable( true ).add( qbeCert ).list( );
261
if( users.isEmpty( ) || users.size( ) > 1 ) {
262
throw new NoSuchCertificateException( "Failed to identify user (found " + users.size() + ") from certificate information: " + cert.getSubjectX500Principal( ).toString( ) );
273
public User lookupQueryId( String queryId ) throws NoSuchUserException {
274
String userName = null;
275
EntityWrapper<UserEntity> db = Authentication.getEntityWrapper( );
276
UserEntity searchUser = new UserEntity( );
277
searchUser.setQueryId( queryId );
278
UserEntity user = null;
280
user = db.getUnique( searchUser );
282
} catch ( Throwable e ) {
284
throw new NoSuchUserException( e );
286
return new DatabaseWrappedUser( user );
290
public User lookupUser( String userName ) throws NoSuchUserException {
291
EntityWrapper<UserEntity> db = Authentication.getEntityWrapper( );
292
UserEntity searchUser = new UserEntity( userName );
293
UserEntity user = null;
295
user = db.getUnique( searchUser );
297
} catch ( Throwable e ) {
299
throw new NoSuchUserException( e );
301
return new DatabaseWrappedUser( user );
305
public Group addGroup( String groupName ) throws GroupExistsException {
306
EntityWrapper<GroupEntity> db = Authentication.getEntityWrapper( );
307
GroupEntity newGroup = new GroupEntity( groupName );
311
} catch ( Throwable t ) {
313
throw new GroupExistsException( t );
315
return DatabaseWrappedGroup.newInstance( newGroup );
319
public List<Group> listAllGroups( ) {
320
List<Group> ret = Lists.newArrayList( );
321
GroupEntity search = new GroupEntity( );
322
EntityWrapper<GroupEntity> db = EntityWrapper.get( search );
323
List<GroupEntity> groupList = db.query( search );
324
for ( GroupEntity g : groupList ) {
325
ret.add( DatabaseWrappedGroup.newInstance( g ) );
330
public void deleteGroup( String groupName ) throws NoSuchGroupException {
331
Groups.checkNotRestricted( groupName );
332
EntityWrapper<GroupEntity> db = Authentication.getEntityWrapper( );
333
GroupEntity delGroup = new GroupEntity( groupName );
335
GroupEntity g = db.getUnique( delGroup );
338
} catch ( Throwable t ) {
340
throw new NoSuchGroupException( t );
345
public void updateUser( String name, Tx<User> userTx ) throws NoSuchUserException {
346
UserEntity search = new UserEntity(name);
347
EntityWrapper<UserEntity> db = EntityWrapper.get( search );
349
UserEntity entity = db.getUnique( search );
350
userTx.fire( entity );
352
} catch ( EucalyptusCloudException e ) {
354
throw new NoSuchUserException( e.getMessage( ), e );
355
} catch ( Throwable e ) {
358
throw new NoSuchUserException( e.getMessage( ), e );
363
public void addUserInfo( UserInfo user ) throws UserExistsException {
364
EntityWrapper<UserInfo> dbWrapper = EntityWrapper.get( UserInfo.class );
366
dbWrapper.add( user );
368
} catch ( Exception e1 ) {
369
dbWrapper.rollback();
371
throw new UserExistsException( "User info exists", e1 );
376
public void deleteUserInfo( String userName ) throws NoSuchUserException {
377
EntityWrapper<UserInfo> dbWrapper = new EntityWrapper<UserInfo>( );
379
UserInfo userInfo = dbWrapper.getUnique( new UserInfo(userName) );
380
dbWrapper.delete( userInfo );
382
} catch ( EucalyptusCloudException e1 ) {
383
dbWrapper.rollback( );
385
throw new NoSuchUserException( "User info does not exist", e1 );
390
public UserInfo getUserInfo( UserInfo search ) throws NoSuchUserException {
391
EntityWrapper<UserInfo> dbWrapper = new EntityWrapper<UserInfo>( );
393
UserInfo userInfo = dbWrapper.getUnique( search );
396
} catch ( EucalyptusCloudException e ) {
397
dbWrapper.rollback( );
398
throw new NoSuchUserException( "User info does not exist", e );
403
public void updateUserInfo( String name, Tx<UserInfo> infoTx ) throws NoSuchUserException {
404
EntityWrapper<UserInfo> dbWrapper = new EntityWrapper<UserInfo>( );
406
UserInfo userInfo = dbWrapper.getUnique( new UserInfo(name) );
407
infoTx.fire( userInfo );
409
} catch ( EucalyptusCloudException e ) {
410
dbWrapper.rollback( );
412
throw new NoSuchUserException( "User info does not exist", e );
413
} catch ( Throwable t ) {
414
dbWrapper.rollback( );
416
throw new NoSuchUserException( "Error in updating user info", t );