1 /*
2 * #%L
3 * CredentialEditor.java - mongodb-async-driver - Allanbank Consulting, Inc.
4 * %%
5 * Copyright (C) 2011 - 2014 Allanbank Consulting, Inc.
6 * %%
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 * #L%
19 */
20 package com.allanbank.mongodb;
21
22 import java.beans.PropertyEditorSupport;
23 import java.util.Collections;
24 import java.util.HashSet;
25 import java.util.Map;
26 import java.util.Set;
27
28 import com.allanbank.mongodb.util.log.Log;
29 import com.allanbank.mongodb.util.log.LogFactory;
30
31 /**
32 * CredentialEditor provides the ability to parse the credentials from a MongoDB
33 * URI.
34 * <p>
35 * This editor will parses a full MongoDB URI to extract the specified
36 * {@link Credential}. See the <a href=
37 * "http://docs.mongodb.org/manual/reference/connection-string/#authentication-options"
38 * >Connection String URI Format</a> documentation for information on
39 * constructing a MongoDB URI.
40 * </p>
41 *
42 * @api.yes This class is part of the driver's API. Public and protected members
43 * will be deprecated for at least 1 non-bugfix release (version
44 * numbers are <major>.<minor>.<bugfix>) before being
45 * removed or modified.
46 * @copyright 2014, Allanbank Consulting, Inc., All Rights Reserved
47 */
48 public class CredentialEditor extends PropertyEditorSupport {
49
50 /**
51 * The fields parsed out of a MongoDB URI to construct a {@link Credential}.
52 */
53 public static final Set<String> MONGODB_URI_FIELDS;
54
55 /** The logger for the {@link CredentialEditor}. */
56 protected static final Log LOG = LogFactory.getLog(CredentialEditor.class);
57
58 static {
59 final Set<String> fields = new HashSet<String>();
60 fields.add("gssapiservicename");
61 fields.add("authsource");
62 fields.add("authmechanism");
63
64 MONGODB_URI_FIELDS = Collections.unmodifiableSet(fields);
65 }
66
67 /**
68 * Creates a new CredentialEditor.
69 */
70 public CredentialEditor() {
71 super();
72 }
73
74 /**
75 * {@inheritDoc}
76 * <p>
77 * Overridden to parse a string to a {@link Credential}.
78 * </p>
79 *
80 * @throws IllegalArgumentException
81 * If the string cannot be parsed into a {@link Credential}.
82 */
83 @Override
84 public void setAsText(final String credentialString)
85 throws IllegalArgumentException {
86
87 if (MongoDbUri.isUri(credentialString)) {
88 Credential.Builder builder = null;
89
90 final MongoDbUri uri = new MongoDbUri(credentialString);
91 if (uri.getUserName() != null) {
92 builder = Credential.builder().userName(uri.getUserName())
93 .password(uri.getPassword().toCharArray());
94 final String database = uri.getDatabase();
95 if (!database.isEmpty()) {
96 builder.database(database);
97 }
98 }
99 final Credential parsed = fromUriParameters(builder,
100 uri.getParsedOptions());
101 if (parsed != null) {
102 setValue(parsed);
103 }
104 }
105 else {
106 throw new IllegalArgumentException(
107 "Could not determine the credentials for '"
108 + credentialString + "'.");
109 }
110 }
111
112 /**
113 * Creates a Credential from the MongoDB URI parameters. Any fields used
114 * from the parameters are removed from the {@code parameters} map.
115 *
116 * @param builder
117 * The credentials builder to update.
118 * @param parameters
119 * The map of URI parameters.
120 * @return The Credential.
121 */
122 private Credential fromUriParameters(final Credential.Builder builder,
123 final Map<String, String> parameters) {
124
125 final String gssapiServiceName = parameters.remove("gssapiservicename");
126 if ((gssapiServiceName != null)) {
127 if (builder != null) {
128 builder.kerberos().addOption("kerberos.service.name",
129 gssapiServiceName);
130 }
131 else {
132 LOG.info("Must supply a user name "
133 + "to set a gssapiServiceName: '{}'.",
134 gssapiServiceName);
135 }
136 }
137
138 final String authSource = parameters.remove("authsource");
139 if (authSource != null) {
140 if (builder != null) {
141 builder.setDatabase(authSource);
142 }
143 else {
144 LOG.info("Must supply a user name "
145 + "to set a authSource: '{}'.", authSource);
146 }
147 }
148
149 final String authMechanism = parameters.remove("authmechanism");
150 if (authMechanism != null) {
151 if (builder != null) {
152 if ("MONGODB-CR".equalsIgnoreCase(authMechanism)) {
153 builder.mongodbCR();
154 }
155 else if ("MONGODB-X509".equalsIgnoreCase(authMechanism)) {
156 builder.x509();
157 }
158 else if ("GSSAPI".equalsIgnoreCase(authMechanism)) {
159 builder.kerberos();
160 }
161 else if ("PLAIN".equalsIgnoreCase(authMechanism)) {
162 builder.plainSasl();
163 }
164 else {
165 LOG.warn("Unknown authMechanism: '{}'. "
166 + "Not authenticating.", authMechanism);
167 }
168 }
169 else {
170 LOG.info("Must supply a user name and password "
171 + "to set a authMechanism: '{}'.", authMechanism);
172 }
173 }
174
175 if (builder != null) {
176 return builder.build();
177 }
178 return null;
179 }
180
181 }