• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

evolvedbinary / elemental / 982

29 Apr 2025 08:34PM UTC coverage: 56.409% (+0.007%) from 56.402%
982

push

circleci

adamretter
[feature] Improve README.md badges

28451 of 55847 branches covered (50.94%)

Branch coverage included in aggregate %.

77468 of 131924 relevant lines covered (58.72%)

0.59 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

55.63
/exist-core/src/main/java/org/exist/security/internal/AccountImpl.java
1
/*
2
 * Elemental
3
 * Copyright (C) 2024, Evolved Binary Ltd
4
 *
5
 * admin@evolvedbinary.com
6
 * https://www.evolvedbinary.com | https://www.elemental.xyz
7
 *
8
 * Use of this software is governed by the Business Source License 1.1
9
 * included in the LICENSE file and at www.mariadb.com/bsl11.
10
 *
11
 * Change Date: 2028-04-27
12
 *
13
 * On the date above, in accordance with the Business Source License, use
14
 * of this software will be governed by the Apache License, Version 2.0.
15
 *
16
 * Additional Use Grant: Production use of the Licensed Work for a permitted
17
 * purpose. A Permitted Purpose is any purpose other than a Competing Use.
18
 * A Competing Use means making the Software available to others in a commercial
19
 * product or service that: substitutes for the Software; substitutes for any
20
 * other product or service we offer using the Software that exists as of the
21
 * date we make the Software available; or offers the same or substantially
22
 * similar functionality as the Software.
23
 *
24
 * NOTE: Parts of this file contain code from 'The eXist-db Authors'.
25
 *       The original license header is included below.
26
 *
27
 * =====================================================================
28
 *
29
 * eXist-db Open Source Native XML Database
30
 * Copyright (C) 2001 The eXist-db Authors
31
 *
32
 * info@exist-db.org
33
 * http://www.exist-db.org
34
 *
35
 * This library is free software; you can redistribute it and/or
36
 * modify it under the terms of the GNU Lesser General Public
37
 * License as published by the Free Software Foundation; either
38
 * version 2.1 of the License, or (at your option) any later version.
39
 *
40
 * This library is distributed in the hope that it will be useful,
41
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
42
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
43
 * Lesser General Public License for more details.
44
 *
45
 * You should have received a copy of the GNU Lesser General Public
46
 * License along with this library; if not, write to the Free Software
47
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
48
 */
49
package org.exist.security.internal;
50

51
import org.exist.security.AbstractRealm;
52
import org.exist.security.AbstractAccount;
53
import org.apache.logging.log4j.LogManager;
54
import org.apache.logging.log4j.Logger;
55
import org.exist.config.Configuration;
56
import org.exist.config.ConfigurationException;
57
import org.exist.config.Configurator;
58
import org.exist.config.annotation.ConfigurationClass;
59
import org.exist.config.annotation.ConfigurationFieldAsElement;
60
import org.exist.security.Group;
61
import org.exist.security.PermissionDeniedException;
62
import org.exist.security.SchemaType;
63
import org.exist.security.SecurityManager;
64
import org.exist.security.Account;
65
import org.exist.security.internal.aider.UserAider;
66

67
import java.io.IOException;
68
import java.io.InputStream;
69
import java.util.ArrayList;
70
import java.util.Optional;
71
import java.util.Properties;
72
import org.exist.security.Credential;
73

74
import org.exist.storage.DBBroker;
75

76
/**
77
 * Represents a user within the database.
78
 * 
79
 * @author <a href="mailto:wolfgang@exist-db.org">Wolfgang Meier</a>
80
 * @author {Marco.Tampucci, Massimo.Martinelli} @isti.cnr.it
81
 * @author <a href="mailto:adam@exist-db.org">Adam retter</a>
82
 */
83
@ConfigurationClass("account")
84
public class AccountImpl extends AbstractAccount {
85

86
    private final static Logger LOG = LogManager.getLogger(AccountImpl.class);
1✔
87
    public static boolean CHECK_PASSWORDS = true;
1✔
88

89
    private final static SecurityProperties securityProperties = new SecurityProperties();
1✔
90

91
    public static SecurityProperties getSecurityProperties() {
92
        return securityProperties;
1✔
93
    }
94

95
    /*
96
    static {
97
        Properties props = new Properties();
98
        try {
99
            props.load(AccountImpl.class.getClassLoader().getResourceAsStream(
100
                    "org/exist/security/security.properties"));
101
        } catch(IOException e) {
102
        }
103
        String option = props.getProperty("passwords.encoding", "md5");
104
        setPasswordEncoding(option);
105
        option = props.getProperty("passwords.check", "yes");
106
        CHECK_PASSWORDS = option.equalsIgnoreCase("yes")
107
                || option.equalsIgnoreCase("true");
108
    }
109

110
    static public void enablePasswordChecks(boolean check) {
111
        CHECK_PASSWORDS = check;
112
    }
113

114
    static public void setPasswordEncoding(String encoding) {
115
        if(encoding != null) {
116
            LOG.equals("Setting password encoding to " + encoding);
117
            if(encoding.equalsIgnoreCase("plain")) {
118
                PASSWORD_ENCODING = PLAIN_ENCODING;
119
            } else if(encoding.equalsIgnoreCase("md5")) {
120
                PASSWORD_ENCODING = MD5_ENCODING;
121
            } else {
122
                PASSWORD_ENCODING = SIMPLE_MD5_ENCODING;
123
            }
124
        }
125
    }*/
126

127
    @ConfigurationFieldAsElement("password")
128
    private String password = null;
1✔
129
    @ConfigurationFieldAsElement("digestPassword")
130
    private String digestPassword = null;
1✔
131

132
    /**
133
     * Create a new user with name and password
134
     * @param broker the DBBroker
135
     * @param realm the security realm
136
     * @param id of the account
137
     * @param name of the account
138
     * @param password of the account
139
     * @throws ConfigurationException if there is an configuration error
140
     */
141
    public AccountImpl(final DBBroker broker, final AbstractRealm realm, final int id, final String name,final  String password) throws ConfigurationException {
142
        super(broker, realm, id, name);
×
143
        setPassword(password);
×
144
    }
×
145

146
    public AccountImpl(final DBBroker broker, final AbstractRealm realm, final int id, final String name, final String password, final Group group, final boolean hasDbaRole) throws ConfigurationException {
147
        super(broker, realm, id, name);
1✔
148
        setPassword(password);
1✔
149
        this.groups.add(group);
1✔
150
        this.hasDbaRole = hasDbaRole;
1✔
151
    }
1✔
152

153
    public AccountImpl(final DBBroker broker, final AbstractRealm realm, final int id, final String name, final String password, final Group group) throws ConfigurationException {
154
        super(broker, realm, id, name);
1✔
155
        setPassword(password);
1✔
156
        this.groups.add(group);
1✔
157
    }
1✔
158

159
    /**
160
     * Create a new user with name
161
     *
162
     * @param broker the DBBroker
163
     * @param realm the security realm
164
     * @param name of the account
165
     *            The account name
166
     * @throws ConfigurationException if there is an configuration error
167
     */
168
    public AccountImpl(final DBBroker broker, final AbstractRealm realm, final String name) throws ConfigurationException {
169
        super(broker, realm, Account.UNDEFINED_ID, name);
×
170
    }
×
171

172
//    /**
173
//     * Create a new user with name, password and primary group
174
//     *
175
//     * @param name
176
//     * @param password
177
//     * @param primaryGroup
178
//     * @throws ConfigurationException
179
//     * @throws PermissionDeniedException
180
//     */
181
//        public AccountImpl(AbstractRealm realm, int id, String name, String password, String primaryGroup) throws ConfigurationException {
182
//                this(realm, id, name, password);
183
//                addGroup(primaryGroup);
184
//        }
185
    
186
    public AccountImpl(final DBBroker broker, final AbstractRealm realm, final int id, final Account from_user) throws ConfigurationException, PermissionDeniedException {
187
        super(broker, realm, id, from_user.getName());
1✔
188
        instantiate(from_user);
1✔
189
    }
1✔
190
    
191
    private void instantiate(final Account from_user) throws PermissionDeniedException {
192

193
        //copy metadata
194
        for(final SchemaType metadataKey : from_user.getMetadataKeys()) {
1✔
195
            final String metadataValue = from_user.getMetadataValue(metadataKey);
1✔
196
            setMetadataValue(metadataKey, metadataValue);
1✔
197
        }
198
        
199
        //copy umask
200
        setUserMask(from_user.getUserMask());
1✔
201

202
        if(from_user instanceof AccountImpl) {
1!
203
            final AccountImpl user = (AccountImpl) from_user;
×
204

205
            groups = new ArrayList<>(user.groups);
×
206

207
            password = user.password;
×
208
            digestPassword = user.digestPassword;
×
209

210
            hasDbaRole = user.hasDbaRole;
×
211

212
            _cred = user._cred;
×
213
        } else if(from_user instanceof UserAider) {
1!
214
            final UserAider user = (UserAider) from_user;
1✔
215

216
            final String[] groups = user.getGroups();
1✔
217
            for (final String group : groups) {
1✔
218
                addGroup(group);
1✔
219
            }
220

221
            setPassword(user.getPassword());
1✔
222
            digestPassword = user.getDigestPassword();
1✔
223
        } else {
1✔
224
            addGroup(from_user.getDefaultGroup());
×
225
            //TODO: groups
226
        }
227
    }
1✔
228

229
    public AccountImpl(final DBBroker broker, final AbstractRealm realm, final AccountImpl from_user) throws ConfigurationException {
230
        super(broker, realm, from_user.id, from_user.name);
×
231

232
        //copy metadata
233
        for(final SchemaType metadataKey : from_user.getMetadataKeys()) {
×
234
            final String metadataValue = from_user.getMetadataValue(metadataKey);
×
235
            setMetadataValue(metadataKey, metadataValue);
×
236
        }
237

238
        groups = from_user.groups;
×
239

240
        password = from_user.password;
×
241
        digestPassword = from_user.digestPassword;
×
242

243
        hasDbaRole = from_user.hasDbaRole;
×
244

245
        _cred = from_user._cred;
×
246

247
        //this.realm = realm;   //set via super()
248
    }
×
249

250
    public AccountImpl(final AbstractRealm realm, final Configuration configuration) throws ConfigurationException {
251
        super(realm, configuration);
1✔
252

253
        //this is required because the classes fields are initialized after the super constructor
254
        if(this.configuration != null) {
1!
255
            this.configuration = Configurator.configure(this, this.configuration);
1✔
256
        }
257
        this.hasDbaRole = this.hasGroup(SecurityManager.DBA_GROUP);
1✔
258
    }
1✔
259

260
    public AccountImpl(final AbstractRealm realm, final Configuration configuration, final boolean removed) throws ConfigurationException {
261
        this(realm, configuration);
×
262
        this.removed = removed;
×
263
    }
×
264

265
    /**
266
     * Get the user's password
267
     *
268
     * @return Description of the Return Value
269
     * @deprecated
270
     */
271
    @Override @Deprecated
272
    public final String getPassword() {
273
        return password;
1✔
274
    }
275

276
    @Override
277
    public final String getDigestPassword() {
278
        return digestPassword;
×
279
    }
280

281
    @Override
282
    public final void setPassword(final String passwd) {
283
        _cred = new Password(this, passwd);
1✔
284

285
        if(passwd == null) {
1✔
286
            this.password = null;
1✔
287
            this.digestPassword = null;
1✔
288
        } else {
1✔
289
            this.password = _cred.toString();
1✔
290
            this.digestPassword = _cred.getDigest();
1✔
291
        }
292
    }
1✔
293

294
    @Override
295
    public void setCredential(final Credential credential) {
296
        this._cred = credential;
1✔
297
        this.password = _cred.toString();
1✔
298
        this.digestPassword = _cred.getDigest();
1✔
299
    }
1✔
300

301
    public final static class SecurityProperties {
1✔
302

303
        private final static boolean DEFAULT_CHECK_PASSWORDS = true;
304

305
        private final static String PROP_CHECK_PASSWORDS = "passwords.check";
306

307
        private Properties loadedSecurityProperties = null;
1✔
308
        private Boolean checkPasswords = null;
1✔
309

310
        public synchronized boolean isCheckPasswords() {
311
            if(checkPasswords == null) {
×
312
                final String property = getProperty(PROP_CHECK_PASSWORDS);
×
313
                if(property == null || property.isEmpty()) {
×
314
                    checkPasswords = DEFAULT_CHECK_PASSWORDS;
×
315
                } else {
×
316
                    checkPasswords = property.equalsIgnoreCase("yes") || property.equalsIgnoreCase("true");
×
317
                }
318
            }
319
            return checkPasswords;
×
320
        }
321

322
        public synchronized void enableCheckPasswords(final boolean enable) {
323
            this.checkPasswords = enable;
1✔
324
        }
1✔
325

326
        private synchronized String getProperty(final String propertyName) {
327
            if(loadedSecurityProperties == null) {
×
328
                loadedSecurityProperties = new Properties();
×
329

330
                try(final InputStream is = AccountImpl.class.getResourceAsStream("security.properties")) {
×
331
                    
332
                    if(is != null) {
×
333
                        loadedSecurityProperties.load(is);
×
334
                    }
335
                } catch(final IOException ioe) {
×
336
                    LOG.error("Unable to load security.properties, using defaults. {}", ioe.getMessage(), ioe);
×
337
                }
338
            }
339
            return loadedSecurityProperties.getProperty(propertyName);
×
340
        }
341
    }
342

343
    //this method is used by Configurator
344
    public final Group insertGroup(final int index, final String name) throws PermissionDeniedException {
345
        //if we cant find the group in our own realm, try other realms
346
        final Group group = Optional.ofNullable(getRealm().getGroup(name))
1✔
347
                .orElse(getRealm().getSecurityManager().getGroup(name));
1✔
348

349
        return insertGroup(index, group);
1✔
350
    }
351

352
    private Group insertGroup(final int index, final Group group) throws PermissionDeniedException {
353

354
        if(group == null){
1!
355
            return null;
×
356
        }
357

358
        final Account user = getDatabase().getActiveBroker().getCurrentSubject();
1✔
359
        group.assertCanModifyGroup(user);
1✔
360

361
        if(!groups.contains(group)) {
1!
362
            groups.add(index, group);
1✔
363

364
            if(SecurityManager.DBA_GROUP.equals(group.getName())) {
1✔
365
                hasDbaRole = true;
1✔
366
            }
367
        }
368

369
        return group;
1✔
370
    }
371
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc