Index: jackrabbit-webapp/src/main/webapp/WEB-INF/web.xml
===================================================================
--- jackrabbit-webapp/src/main/webapp/WEB-INF/web.xml (revision 936184)
+++ jackrabbit-webapp/src/main/webapp/WEB-INF/web.xml (revision )
@@ -204,6 +204,10 @@
The webdav servlet that connects HTTP request to the repository.
org.apache.jackrabbit.j2ee.SimpleWebdavServlet
+
resource-path-prefix
Index: jackrabbit-core/src/test/resources/passwords.properties
===================================================================
--- jackrabbit-core/src/test/resources/passwords.properties (revision )
+++ jackrabbit-core/src/test/resources/passwords.properties (revision )
@@ -0,0 +1,2 @@
+#Digest of fakeuser:jackrabbit:fakepassword
+fakeuser=5d03107efa7fc691c6b34271fc28004c
\ No newline at end of file
Index: jackrabbit-core/src/test/java/org/apache/jackrabbit/core/security/authentication/TestAll.java
===================================================================
--- jackrabbit-core/src/test/java/org/apache/jackrabbit/core/security/authentication/TestAll.java (revision 961487)
+++ jackrabbit-core/src/test/java/org/apache/jackrabbit/core/security/authentication/TestAll.java (revision )
@@ -31,6 +31,7 @@
suite.addTestSuite(SimpleCredentialsAuthenticationTest.class);
suite.addTestSuite(CryptedSimpleCredentialsTest.class);
suite.addTestSuite(LoginModuleTest.class);
+ suite.addTestSuite(DigestAuthenticationTest.class);
return suite;
}
Index: jackrabbit-webapp/src/main/java/org/apache/jackrabbit/j2ee/DigestWebdavServlet.java
===================================================================
--- jackrabbit-webapp/src/main/java/org/apache/jackrabbit/j2ee/DigestWebdavServlet.java (revision )
+++ jackrabbit-webapp/src/main/java/org/apache/jackrabbit/j2ee/DigestWebdavServlet.java (revision )
@@ -0,0 +1,77 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.j2ee;
+
+import org.apache.jackrabbit.server.CredentialsProvider;
+import org.apache.jackrabbit.server.DigestCredentialsProvider;
+import org.apache.jackrabbit.util.Text;
+import org.apache.jackrabbit.webdav.DavException;
+import org.apache.jackrabbit.webdav.WebdavRequest;
+import org.apache.jackrabbit.webdav.WebdavResponse;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+
+/**
+ * Extension of the standard WebDAV servlet to support HTTP Digest authentication.
+ */
+public class DigestWebdavServlet extends SimpleWebdavServlet {
+
+ private static final long serialVersionUID = 7796841861774352679L;
+
+ private static final Logger log = LoggerFactory.getLogger(DigestWebdavServlet.class);
+
+ private static final String key = "jackrabbit";
+
+ private static final String realmName = "jackrabbit";
+
+ @Override
+ protected void sendUnauthorized(WebdavRequest request,
+ WebdavResponse response, DavException error) throws IOException {
+
+ String nOnce = generateNOnce(request);
+
+ String header = "Digest realm=\"" + realmName + "\", "
+ + "qop=\"auth\", nonce=\"" + nOnce + "\", " + "opaque=\""
+ + Text.md5(nOnce) + "\"";
+
+ if (log.isDebugEnabled()) {
+ log.debug("WWW-Authenticate " + header);
+ }
+ response.setHeader("WWW-Authenticate", header);
+ response.sendError(HttpServletResponse.SC_UNAUTHORIZED);
+ }
+
+ @Override
+ protected CredentialsProvider getCredentialsProvider() {
+ return new DigestCredentialsProvider();
+ }
+
+ protected String generateNOnce(HttpServletRequest request) {
+
+ long currentTime = System.currentTimeMillis();
+
+ String nOnceValue = request.getRemoteAddr() + ":" +
+ currentTime + ":" + key;
+
+ return Text.md5(nOnceValue);
+ }
+
+}
Index: jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/util/DigestPasswordUtil.java
===================================================================
--- jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/util/DigestPasswordUtil.java (revision )
+++ jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/util/DigestPasswordUtil.java (revision )
@@ -0,0 +1,44 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.util;
+
+/**
+ * Utility to generate a password digest
+ */
+public class DigestPasswordUtil {
+
+ /**
+ * Generated the digest of the sequence username:realm:password.
+ * @param username The username
+ * @param realm The realm
+ * @param password The clear-text password
+ * @return Digest of the parameters
+ */
+ public static String digest(String username, String realm, String password) {
+ return Text.md5(username + ":" + realm + ":" + password);
+ }
+
+ public static void main(String args[]) {
+ if (args.length != 3) {
+ System.out.println("Usage: " + DigestPasswordUtil.class.getName()
+ + " ");
+ } else {
+ System.out.println(args[0] + "=" + digest(args[0], args[1], args[2]));
+ }
+ }
+
+}
Index: jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/simple/DigestLoginModule.java
===================================================================
--- jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/simple/DigestLoginModule.java (revision )
+++ jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/simple/DigestLoginModule.java (revision )
@@ -0,0 +1,89 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.core.security.simple;
+
+import org.apache.jackrabbit.commons.DigestCredentials;
+import org.apache.jackrabbit.core.security.authentication.Authentication;
+import org.apache.jackrabbit.core.security.authentication.DigestAuthentication;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.jcr.Credentials;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+import javax.security.auth.callback.CallbackHandler;
+import javax.security.auth.login.LoginException;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.security.Principal;
+import java.security.acl.Group;
+import java.util.Map;
+
+/**
+ * Login module implementation to support HTTP Digest authentication
+ */
+public class DigestLoginModule extends SimpleLoginModule {
+
+ private static final Logger log = LoggerFactory
+ .getLogger(DigestLoginModule.class);
+
+ private static final String PASSWORDS_FILE_OPTION = "passwordsFile";
+
+ private String passwordsFile = "";
+
+ @Override
+ protected void doInit(CallbackHandler callbackHandler, Session session, Map options)
+ throws LoginException {
+ super.doInit(callbackHandler, session, options);
+
+ if (options.containsKey(PASSWORDS_FILE_OPTION)) {
+ passwordsFile = (String) options.get(PASSWORDS_FILE_OPTION);
+ } else {
+ throw new LoginException("The mandatory parameter '" + PASSWORDS_FILE_OPTION +
+ "' is missing.");
+ }
+
+ }
+
+ @Override
+ protected Authentication getAuthentication(Principal principal,
+ Credentials creds) throws RepositoryException {
+ if (principal instanceof Group) {
+ return null;
+ }
+ try {
+ return new DigestAuthentication(new FileInputStream(passwordsFile));
+ } catch (FileNotFoundException e) {
+ throw new RepositoryException("The file '" + passwordsFile + "' could not be found.",e);
+ }
+ }
+
+ @Override
+ protected boolean supportsCredentials(Credentials creds) {
+ return creds instanceof DigestCredentials;
+ }
+
+ @Override
+ protected String getUserID(Credentials credentials) {
+ String userId = ((DigestCredentials) credentials).getUsername();
+ if (userId == null) {
+ return super.getUserID(credentials);
+ }
+ return userId;
+ }
+
+}
Index: jackrabbit-core/src/test/java/org/apache/jackrabbit/core/security/authentication/DigestAuthenticationTest.java
===================================================================
--- jackrabbit-core/src/test/java/org/apache/jackrabbit/core/security/authentication/DigestAuthenticationTest.java (revision )
+++ jackrabbit-core/src/test/java/org/apache/jackrabbit/core/security/authentication/DigestAuthenticationTest.java (revision )
@@ -0,0 +1,65 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.core.security.authentication;
+
+import org.apache.jackrabbit.commons.DigestCredentials;
+import org.apache.jackrabbit.test.AbstractJCRTest;
+import org.apache.jackrabbit.util.DigestPasswordUtil;
+import org.apache.jackrabbit.util.Text;
+
+import java.io.InputStream;
+
+public class DigestAuthenticationTest extends AbstractJCRTest {
+
+ private Authentication authentication;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ InputStream is = getClass().getResourceAsStream("/passwords.properties");
+ authentication = new DigestAuthentication(is);
+ }
+
+ public void testAuthenticationFailed() throws Exception {
+ DigestCredentials cred = new DigestCredentials();
+ cred.setUsername("foo");
+ assertFalse(authentication.authenticate(cred));
+
+ }
+
+ public void testSuccessfulAuthentication() throws Exception {
+ DigestCredentials cred = new DigestCredentials();
+ cred.setUsername("fakeuser");
+ cred.setRealm("jackrabbit");
+
+ cred.setNonce("nonce");
+ cred.setNc("nc");
+ cred.setCnonce("cnonce");
+ cred.setQop("qop");
+ cred.setMd5a2("md5a2");
+
+ String passwordDigest = DigestPasswordUtil.digest("fakeuser", "jackrabbit", "fakepassword");
+
+ String clientDigest = Text.md5(passwordDigest + ":" + cred.getNonce() + ":" + cred.getNc()
+ + ":" + cred.getCnonce() + ":" + cred.getQop() + ":" + cred.getMd5a2());
+
+ cred.setClientDigest(clientDigest);
+
+ assertTrue(authentication.authenticate(cred));
+ }
+
+}
Index: jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/commons/DigestCredentials.java
===================================================================
--- jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/commons/DigestCredentials.java (revision )
+++ jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/commons/DigestCredentials.java (revision )
@@ -0,0 +1,83 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.commons;
+
+import javax.jcr.Credentials;
+
+/**
+ * Credentials used for HTTP Digest authentication
+ */
+public class DigestCredentials implements Credentials {
+
+ private String username;
+ private String clientDigest;
+ private String nonce;
+ private String nc;
+ private String cnonce;
+ private String qop;
+ private String realm;
+ private String md5a2;
+ public String getUsername() {
+ return username;
+ }
+ public void setUsername(String username) {
+ this.username = username;
+ }
+ public String getClientDigest() {
+ return clientDigest;
+ }
+ public void setClientDigest(String clientDigest) {
+ this.clientDigest = clientDigest;
+ }
+ public String getNonce() {
+ return nonce;
+ }
+ public void setNonce(String nonce) {
+ this.nonce = nonce;
+ }
+ public String getNc() {
+ return nc;
+ }
+ public void setNc(String nc) {
+ this.nc = nc;
+ }
+ public String getCnonce() {
+ return cnonce;
+ }
+ public void setCnonce(String cnonce) {
+ this.cnonce = cnonce;
+ }
+ public String getQop() {
+ return qop;
+ }
+ public void setQop(String qop) {
+ this.qop = qop;
+ }
+ public String getRealm() {
+ return realm;
+ }
+ public void setRealm(String realm) {
+ this.realm = realm;
+ }
+ public String getMd5a2() {
+ return md5a2;
+ }
+ public void setMd5a2(String md5a2) {
+ this.md5a2 = md5a2;
+ }
+
+}
Index: jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authentication/DigestAuthentication.java
===================================================================
--- jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authentication/DigestAuthentication.java (revision )
+++ jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authentication/DigestAuthentication.java (revision )
@@ -0,0 +1,91 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.core.security.authentication;
+
+import org.apache.jackrabbit.commons.DigestCredentials;
+import org.apache.jackrabbit.util.Text;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.jcr.Credentials;
+import javax.jcr.RepositoryException;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Properties;
+
+/**
+ * Implementation of HTTP Digest authentication
+ */
+public class DigestAuthentication implements Authentication {
+
+ private static final Logger log = LoggerFactory
+ .getLogger(DigestAuthentication.class);
+
+ private Properties passwords;
+
+ public DigestAuthentication(InputStream is) {
+ passwords = new Properties();
+ try {
+ passwords.load(is);
+ } catch (IOException e) {
+ log.error("The passwords file could not be read.", e);
+ }
+ }
+
+ public boolean canHandle(Credentials credentials) {
+ return (credentials != null && credentials instanceof DigestCredentials);
+ }
+
+ public boolean authenticate(Credentials credentials)
+ throws RepositoryException {
+ DigestCredentials dc = (DigestCredentials) credentials;
+
+ return authenticate(dc.getUsername(), dc.getClientDigest(),
+ dc.getNonce(), dc.getNc(), dc.getCnonce(), dc.getQop(),
+ dc.getRealm(), dc.getMd5a2());
+ }
+
+ public boolean authenticate(String username, String clientDigest,
+ String nOnce, String nc, String cnonce, String qop,
+ String realm, String md5a2) {
+
+ String md5a1 = getDigestedPassword(username);
+
+
+ String serverDigestValue = md5a1 + ":" + nOnce + ":" + nc + ":"
+ + cnonce + ":" + qop + ":" + md5a2;
+
+ String serverDigest = Text.md5(serverDigestValue);
+
+ if (log.isDebugEnabled()) {
+ log.debug("Digest : " + clientDigest + " Username:" + username
+ + " nOnce:" + nOnce
+ + " nc:" + nc + " cnonce:" + cnonce + " qop:" + qop
+ + " realm:" + realm + "md5a2:" + md5a2
+ + " Server digest:" + serverDigest);
+ }
+
+ return (serverDigest.equals(clientDigest));
+ }
+
+ protected String getDigestedPassword(String user) {
+ return this.passwords.getProperty(user);
+ }
+
+}
Index: jackrabbit-jcr-server/src/main/java/org/apache/jackrabbit/server/DigestCredentialsProvider.java
===================================================================
--- jackrabbit-jcr-server/src/main/java/org/apache/jackrabbit/server/DigestCredentialsProvider.java (revision )
+++ jackrabbit-jcr-server/src/main/java/org/apache/jackrabbit/server/DigestCredentialsProvider.java (revision )
@@ -0,0 +1,146 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.server;
+
+import javax.jcr.Credentials;
+import javax.jcr.LoginException;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+
+import org.apache.jackrabbit.commons.DigestCredentials;
+import org.apache.jackrabbit.util.Text;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * This Class implements a credentials provider that extracts the credentials
+ * from the 'WWW-Authenticate' header and only supports 'Digest' authentication.
+ */
+public class DigestCredentialsProvider implements CredentialsProvider {
+
+ private static final Logger log = LoggerFactory
+ .getLogger(DigestCredentialsProvider.class);
+
+ public Credentials getCredentials(HttpServletRequest request)
+ throws LoginException, ServletException {
+ String authorization = request.getHeader("authorization");
+ if (authorization == null || authorization.isEmpty()) {
+ // User is not logged in, prompt for credentials
+ throw new LoginException();
+ }
+ if (log.isDebugEnabled()) {
+ log.debug("authorization: " + authorization);
+ }
+ return createDigestCredentials(request, authorization);
+ }
+
+ protected DigestCredentials createDigestCredentials(
+ HttpServletRequest request, String authorization) {
+ if (authorization == null)
+ return (null);
+ if (!authorization.startsWith("Digest "))
+ return (null);
+ authorization = authorization.substring(7).trim();
+
+ String[] tokens = authorization.split(",(?=(?:[^\"]*\"[^\"]*\")+$)");
+
+ String userName = null;
+ String realmName = null;
+ String nOnce = null;
+ String nc = null;
+ String cnonce = null;
+ String qop = null;
+ String uri = null;
+ String response = null;
+ String method = request.getMethod();
+
+ for(String currentToken : tokens) {
+ if (currentToken.length() == 0)
+ continue;
+
+ int equalSign = currentToken.indexOf('=');
+ if (equalSign < 0)
+ return null;
+ String currentTokenName = currentToken.substring(0, equalSign)
+ .trim();
+ String currentTokenValue = currentToken.substring(equalSign + 1)
+ .trim();
+ if ("username".equals(currentTokenName))
+ userName = removeQuotes(currentTokenValue);
+ if ("realm".equals(currentTokenName))
+ realmName = removeQuotes(currentTokenValue, true);
+ if ("nonce".equals(currentTokenName))
+ nOnce = removeQuotes(currentTokenValue);
+ if ("nc".equals(currentTokenName))
+ nc = removeQuotes(currentTokenValue);
+ if ("cnonce".equals(currentTokenName))
+ cnonce = removeQuotes(currentTokenValue);
+ if ("qop".equals(currentTokenName))
+ qop = removeQuotes(currentTokenValue);
+ if ("uri".equals(currentTokenName))
+ uri = removeQuotes(currentTokenValue);
+ if ("response".equals(currentTokenName))
+ response = removeQuotes(currentTokenValue);
+ }
+
+ if ((userName == null) || (realmName == null) || (nOnce == null)
+ || (uri == null) || (response == null))
+ return null;
+
+ // Second MD5 digest used to calculate the digest :
+ // MD5(Method + ":" + uri)
+ String a2 = method + ":" + uri;
+ String md5a2 = Text.md5(a2);
+
+ DigestCredentials dc = new DigestCredentials();
+ dc.setUsername(userName);
+ dc.setClientDigest(response);
+ dc.setNonce(nOnce);
+ dc.setNc(nc);
+ dc.setCnonce(cnonce);
+ dc.setQop(qop);
+ dc.setRealm(realmName);
+ dc.setMd5a2(md5a2);
+ return dc;
+
+ }
+
+ /**
+ * Removes the quotes on a string. RFC2617 states quotes are optional for
+ * all parameters except realm.
+ */
+ protected static String removeQuotes(String quotedString,
+ boolean quotesRequired) {
+ //support both quoted and non-quoted
+ if (quotedString.length() > 0 && quotedString.charAt(0) != '"' &&
+ !quotesRequired) {
+ return quotedString;
+ } else if (quotedString.length() > 2) {
+ return quotedString.substring(1, quotedString.length() - 1);
+ } else {
+ return "";
+ }
+ }
+
+ /**
+ * Removes the quotes on a string.
+ */
+ protected static String removeQuotes(String quotedString) {
+ return removeQuotes(quotedString, false);
+ }
+
+}