diff --git a/src/main/java/org/olat/core/commons/services/webdav/manager/DigestAuthentication.java b/src/main/java/org/olat/core/commons/services/webdav/manager/DigestAuthentication.java index ac2fbe52b76256ebc5cded9428525065396eafb3..f4a7afdd302040e32a0a754c78c3b585f1ba8d8b 100644 --- a/src/main/java/org/olat/core/commons/services/webdav/manager/DigestAuthentication.java +++ b/src/main/java/org/olat/core/commons/services/webdav/manager/DigestAuthentication.java @@ -19,7 +19,13 @@ */ package org.olat.core.commons.services.webdav.manager; -import java.util.StringTokenizer; +import java.io.IOException; +import java.io.StringReader; +import java.util.Map; + +import org.olat.core.logging.OLog; +import org.olat.core.logging.Tracing; +import org.olat.core.util.http.Authorization; /** * @@ -31,6 +37,8 @@ import java.util.StringTokenizer; */ public class DigestAuthentication { + private static final OLog log = Tracing.createLoggerFor(DigestAuthentication.class); + private final String username; private final String realm; private final String nonce; @@ -83,7 +91,7 @@ public class DigestAuthentication { return qop; } - public static DigestAuthentication parse(String request) { + public static DigestAuthentication parse(String header) { String username = null; String realm = null; String nonce = null; @@ -92,30 +100,19 @@ public class DigestAuthentication { String nc = null; String response = null; String qop = null; - - StringTokenizer tokenizer = new StringTokenizer(request, ",\n"); - for(; tokenizer.hasMoreTokens(); ) { - String token=tokenizer.nextToken().trim(); - int index = token.indexOf('='); - String key = token.substring(0, index); - String val = token.substring(index + 1, token.length()).replace("\"", ""); - if("username".equals(key)) { - username = val; - } else if("realm".equals(key)) { - realm = val; - } else if("nonce".equals(key)) { - nonce = val; - } else if("uri".equals(key)) { - uri = val; - } else if("cnonce".equals(key)) { - cnonce = val; - } else if("nc".equals(key)) { - nc = val; - } else if("response".equals(key)) { - response = val; - } else if("qop".equals(key)) { - qop = val; - } + + try { + Map<String,String> parsedHeader = Authorization.parseAuthorizationDigest(new StringReader(header)); + username = parsedHeader.get("username"); + realm = parsedHeader.get("realm"); + nonce = parsedHeader.get("nonce"); + uri = parsedHeader.get("uri"); + cnonce = parsedHeader.get("cnonce"); + nc = parsedHeader.get("nc"); + response = parsedHeader.get("response"); + qop = parsedHeader.get("qop"); + } catch (IOException | IllegalArgumentException e) { + log.error("", e); } return new DigestAuthentication(username, realm, nonce, uri, cnonce, nc, response, qop); } diff --git a/src/main/java/org/olat/core/commons/services/webdav/manager/WebDAVManagerImpl.java b/src/main/java/org/olat/core/commons/services/webdav/manager/WebDAVManagerImpl.java index 187a107fa0367a91d16c01f9826a6a38bd90690a..f320b8c71f48d19a60235bbcb7faf8c4fabd6fed 100644 --- a/src/main/java/org/olat/core/commons/services/webdav/manager/WebDAVManagerImpl.java +++ b/src/main/java/org/olat/core/commons/services/webdav/manager/WebDAVManagerImpl.java @@ -202,13 +202,11 @@ public class WebDAVManagerImpl implements WebDAVManager, InitializingBean { usess = handleBasicAuthentication(credentials, request); } } else if (basic.equalsIgnoreCase("Digest")) { - int digestIndex = authHeader.indexOf("Digest"); - String digestInfos = authHeader.substring(digestIndex + 7); - DigestAuthentication digestAuth = DigestAuthentication.parse(digestInfos); + DigestAuthentication digestAuth = DigestAuthentication.parse(authHeader); cacheKey = digestAuth.getUsername(); usess = timedSessionCache.get(new CacheKey(remoteAddr, digestAuth.getUsername())); if (usess == null || !usess.isAuthenticated()) { - usess = handleDigestAuthentication(digestInfos, request); + usess = handleDigestAuthentication(digestAuth, request); } } } @@ -241,8 +239,7 @@ public class WebDAVManagerImpl implements WebDAVManager, InitializingBean { return null; } - protected UserSession handleDigestAuthentication(String credentials, HttpServletRequest request) { - DigestAuthentication digestAuth = DigestAuthentication.parse(credentials); + protected UserSession handleDigestAuthentication(DigestAuthentication digestAuth, HttpServletRequest request) { Identity identity = webDAVAuthManager.digestAuthentication(request.getMethod(), digestAuth); if(identity != null) { return afterAuthorization(identity, request); diff --git a/src/main/java/org/olat/core/util/http/Authorization.java b/src/main/java/org/olat/core/util/http/Authorization.java new file mode 100644 index 0000000000000000000000000000000000000000..8916b76b9319a8c1c51d9b8037c6db882df305b0 --- /dev/null +++ b/src/main/java/org/olat/core/util/http/Authorization.java @@ -0,0 +1,141 @@ +/* + * 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.olat.core.util.http; + +import java.io.IOException; +import java.io.StringReader; +import java.util.HashMap; +import java.util.Locale; +import java.util.Map; + +/** + * Parser for an "Authorization" header. + */ +public class Authorization { + + @SuppressWarnings("unused") // Unused due to buggy client implementations + private static final Integer FIELD_TYPE_TOKEN = Integer.valueOf(0); + private static final Integer FIELD_TYPE_QUOTED_STRING = Integer.valueOf(1); + private static final Integer FIELD_TYPE_TOKEN_OR_QUOTED_STRING = Integer.valueOf(2); + private static final Integer FIELD_TYPE_LHEX = Integer.valueOf(3); + private static final Integer FIELD_TYPE_QUOTED_TOKEN = Integer.valueOf(4); + + private static final Map<String,Integer> fieldTypes = new HashMap<>(); + + static { + // Digest field types. + // Note: These are more relaxed than RFC2617. This adheres to the + // recommendation of RFC2616 that servers are tolerant of buggy + // clients when they can be so without ambiguity. + fieldTypes.put("username", FIELD_TYPE_QUOTED_STRING); + fieldTypes.put("realm", FIELD_TYPE_QUOTED_STRING); + fieldTypes.put("nonce", FIELD_TYPE_QUOTED_STRING); + fieldTypes.put("digest-uri", FIELD_TYPE_QUOTED_STRING); + // RFC2617 says response is <">32LHEX<">. 32LHEX will also be accepted + fieldTypes.put("response", FIELD_TYPE_LHEX); + // RFC2617 says algorithm is token. <">token<"> will also be accepted + fieldTypes.put("algorithm", FIELD_TYPE_QUOTED_TOKEN); + fieldTypes.put("cnonce", FIELD_TYPE_QUOTED_STRING); + fieldTypes.put("opaque", FIELD_TYPE_QUOTED_STRING); + // RFC2617 says qop is token. <">token<"> will also be accepted + fieldTypes.put("qop", FIELD_TYPE_QUOTED_TOKEN); + // RFC2617 says nc is 8LHEX. <">8LHEX<"> will also be accepted + fieldTypes.put("nc", FIELD_TYPE_LHEX); + + } + + /** + * Parses an HTTP Authorization header for DIGEST authentication as per RFC + * 2617 section 3.2.2. + * + * @param input The header value to parse + * + * @return A map of directives and values as {@link String}s or + * <code>null</code> if a parsing error occurs. Although the + * values returned are {@link String}s they will have been + * validated to ensure that they conform to RFC 2617. + * + * @throws IllegalArgumentException If the header does not conform to RFC + * 2617 + * @throws java.io.IOException If an error occurs while reading the input + */ + public static Map<String,String> parseAuthorizationDigest (StringReader input) + throws IllegalArgumentException, IOException { + + Map<String,String> result = new HashMap<>(); + + if (HttpParser.skipConstant(input, "Digest") != SkipResult.FOUND) { + return null; + } + // All field names are valid tokens + String field = HttpParser.readToken(input); + if (field == null) { + return null; + } + while (!field.equals("")) { + if (HttpParser.skipConstant(input, "=") != SkipResult.FOUND) { + return null; + } + String value; + Integer type = fieldTypes.get(field.toLowerCase(Locale.ENGLISH)); + if (type == null) { + // auth-param = token "=" ( token | quoted-string ) + type = FIELD_TYPE_TOKEN_OR_QUOTED_STRING; + } + switch (type.intValue()) { + case 0: + // FIELD_TYPE_TOKEN + value = HttpParser.readToken(input); + break; + case 1: + // FIELD_TYPE_QUOTED_STRING + value = HttpParser.readQuotedString(input, false); + break; + case 2: + // FIELD_TYPE_TOKEN_OR_QUOTED_STRING + value = HttpParser.readTokenOrQuotedString(input, false); + break; + case 3: + // FIELD_TYPE_LHEX + value = HttpParser.readLhex(input); + break; + case 4: + // FIELD_TYPE_QUOTED_TOKEN + value = HttpParser.readQuotedToken(input); + break; + default: + // Error + throw new IllegalArgumentException("TODO i18n: Unsupported type"); + } + + if (value == null) { + return null; + } + result.put(field, value); + + if (HttpParser.skipConstant(input, ",") == SkipResult.NOT_FOUND) { + return null; + } + field = HttpParser.readToken(input); + if (field == null) { + return null; + } + } + + return result; + } +} diff --git a/src/main/java/org/olat/core/util/http/HttpParser.java b/src/main/java/org/olat/core/util/http/HttpParser.java new file mode 100644 index 0000000000000000000000000000000000000000..640b1a955ef354ca98d663b76aff1992e4dec5d4 --- /dev/null +++ b/src/main/java/org/olat/core/util/http/HttpParser.java @@ -0,0 +1,401 @@ +/* + * 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.olat.core.util.http; + +import java.io.IOException; +import java.io.StringReader; + +/** + * HTTP header value parser implementation. Parsing HTTP headers as per RFC2616 + * is not always as simple as it first appears. For headers that only use tokens + * the simple approach will normally be sufficient. However, for the other + * headers, while simple code meets 99.9% of cases, there are often some edge + * cases that make things far more complicated. + * + * The purpose of this parser is to let the parser worry about the edge cases. + * It provides tolerant (where safe to do so) parsing of HTTP header values + * assuming that wrapped header lines have already been unwrapped. (The Tomcat + * header processing code does the unwrapping.) + * + */ +public class HttpParser { + + // Arrays used by isToken(), isHex() + private static final boolean isToken[] = new boolean[128]; + private static final boolean isHex[] = new boolean[128]; + + static { + // Setup the flag arrays + for (int i = 0; i < 128; i++) { + if (i < 32) { + isToken[i] = false; + } else if (i == '(' || i == ')' || i == '<' || i == '>' || i == '@' || + i == ',' || i == ';' || i == ':' || i == '\\' || i == '\"' || + i == '/' || i == '[' || i == ']' || i == '?' || i == '=' || + i == '{' || i == '}' || i == ' ' || i == '\t') { + isToken[i] = false; + } else { + isToken[i] = true; + } + + if (i >= '0' && i <= '9' || i >= 'A' && i <= 'F' || + i >= 'a' && i <= 'f') { + isHex[i] = true; + } else { + isHex[i] = false; + } + } + } + + public static String unquote(String input) { + if (input == null || input.length() < 2 || input.charAt(0) != '"') { + return input; + } + + StringBuilder result = new StringBuilder(); + for (int i = 1 ; i < (input.length() - 1); i++) { + char c = input.charAt(i); + if (input.charAt(i) == '\\') { + i++; + result.append(input.charAt(i)); + } else { + result.append(c); + } + } + return result.toString(); + } + + static boolean isToken(int c) { + // Fast for correct values, slower for incorrect ones + try { + return isToken[c]; + } catch (ArrayIndexOutOfBoundsException ex) { + return false; + } + } + + static boolean isHex(int c) { + // Fast for correct values, slower for incorrect ones + try { + return isHex[c]; + } catch (ArrayIndexOutOfBoundsException ex) { + return false; + } + } + + // Skip any LWS and return the next char + static int skipLws(StringReader input, boolean withReset) throws IOException { + + if (withReset) { + input.mark(1); + } + int c = input.read(); + + while (c == 32 || c == 9 || c == 10 || c == 13) { + if (withReset) { + input.mark(1); + } + c = input.read(); + } + + if (withReset) { + input.reset(); + } + return c; + } + + static SkipResult skipConstant(StringReader input, String constant) throws IOException { + int len = constant.length(); + + int c = skipLws(input, false); + + for (int i = 0; i < len; i++) { + if (i == 0 && c == -1) { + return SkipResult.EOF; + } + if (c != constant.charAt(i)) { + input.skip(-(i + 1)); + return SkipResult.NOT_FOUND; + } + if (i != (len - 1)) { + c = input.read(); + } + } + return SkipResult.FOUND; + } + + /** + * @return the token if one was found, the empty string if no data was + * available to read or <code>null</code> if data other than a + * token was found + */ + static String readToken(StringReader input) throws IOException { + StringBuilder result = new StringBuilder(); + + int c = skipLws(input, false); + + while (c != -1 && isToken(c)) { + result.append((char) c); + c = input.read(); + } + // Skip back so non-token character is available for next read + input.skip(-1); + + if (c != -1 && result.length() == 0) { + return null; + } else { + return result.toString(); + } + } + + /** + * @return the quoted string if one was found, null if data other than a + * quoted string was found or null if the end of data was reached + * before the quoted string was terminated + */ + static String readQuotedString(StringReader input, boolean returnQuoted) throws IOException { + + int c = skipLws(input, false); + + if (c != '"') { + return null; + } + + StringBuilder result = new StringBuilder(); + if (returnQuoted) { + result.append('\"'); + } + c = input.read(); + + while (c != '"') { + if (c == -1) { + return null; + } else if (c == '\\') { + c = input.read(); + if (returnQuoted) { + result.append('\\'); + } + result.append(c); + } else { + result.append((char) c); + } + c = input.read(); + } + if (returnQuoted) { + result.append('\"'); + } + + return result.toString(); + } + + static String readTokenOrQuotedString(StringReader input, boolean returnQuoted) + throws IOException { + + // Go back so first non-LWS character is available to be read again + int c = skipLws(input, true); + + if (c == '"') { + return readQuotedString(input, returnQuoted); + } else { + return readToken(input); + } + } + + /** + * Token can be read unambiguously with or without surrounding quotes so + * this parsing method for token permits optional surrounding double quotes. + * This is not defined in any RFC. It is a special case to handle data from + * buggy clients (known buggy clients for DIGEST auth include Microsoft IE 8 + * & 9, Apple Safari for OSX and iOS) that add quotes to values that + * should be tokens. + * + * @return the token if one was found, null if data other than a token or + * quoted token was found or null if the end of data was reached + * before a quoted token was terminated + */ + static String readQuotedToken(StringReader input) throws IOException { + + StringBuilder result = new StringBuilder(); + boolean quoted = false; + + int c = skipLws(input, false); + + if (c == '"') { + quoted = true; + } else if (c == -1 || !isToken(c)) { + return null; + } else { + result.append((char) c); + } + c = input.read(); + + while (c != -1 && isToken(c)) { + result.append((char) c); + c = input.read(); + } + + if (quoted) { + if (c != '"') { + return null; + } + } else { + // Skip back so non-token character is available for next read + input.skip(-1); + } + + if (c != -1 && result.length() == 0) { + return null; + } else { + return result.toString(); + } + } + + /** + * LHEX can be read unambiguously with or without surrounding quotes so this + * parsing method for LHEX permits optional surrounding double quotes. Some + * buggy clients (libwww-perl for DIGEST auth) are known to send quoted LHEX + * when the specification requires just LHEX. + * + * <p> + * LHEX are, literally, lower-case hexadecimal digits. This implementation + * allows for upper-case digits as well, converting the returned value to + * lower-case. + * + * @return the sequence of LHEX (minus any surrounding quotes) if any was + * found, or <code>null</code> if data other LHEX was found + */ + static String readLhex(StringReader input) throws IOException { + + StringBuilder result = new StringBuilder(); + boolean quoted = false; + + int c = skipLws(input, false); + + if (c == '"') { + quoted = true; + } else if (c == -1 || !isHex(c)) { + return null; + } else { + if ('A' <= c && c <= 'F') { + c -= ('A' - 'a'); + } + result.append((char) c); + } + c = input.read(); + + while (c != -1 && isHex(c)) { + if ('A' <= c && c <= 'F') { + c -= ('A' - 'a'); + } + result.append((char) c); + c = input.read(); + } + + if (quoted) { + if (c != '"') { + return null; + } + } else { + // Skip back so non-hex character is available for next read + input.skip(-1); + } + + if (c != -1 && result.length() == 0) { + return null; + } else { + return result.toString(); + } + } + + static double readWeight(StringReader input, char delimiter) throws IOException { + int c = skipLws(input, false); + if (c == -1 || c == delimiter) { + // No q value just whitespace + return 1; + } else if (c != 'q') { + // Malformed. Use quality of zero so it is dropped. + skipUntil(input, c, delimiter); + return 0; + } + // RFC 7231 does not allow whitespace here but be tolerant + c = skipLws(input, false); + if (c != '=') { + // Malformed. Use quality of zero so it is dropped. + skipUntil(input, c, delimiter); + return 0; + } + + // RFC 7231 does not allow whitespace here but be tolerant + c = skipLws(input, false); + + // Should be no more than 3 decimal places + StringBuilder value = new StringBuilder(5); + int decimalPlacesRead = 0; + if (c == '0' || c == '1') { + value.append((char) c); + c = input.read(); + if (c == '.') { + value.append('.'); + } else if (c < '0' || c > '9') { + decimalPlacesRead = 3; + } + while (true) { + c = input.read(); + if (c >= '0' && c <= '9') { + if (decimalPlacesRead < 3) { + value.append((char) c); + decimalPlacesRead++; + } + } else if (c == delimiter || c == 9 || c == 32 || c == -1) { + break; + } else { + // Malformed. Use quality of zero so it is dropped and skip until + // EOF or the next delimiter + skipUntil(input, c, delimiter); + return 0; + } + } + } else { + // Malformed. Use quality of zero so it is dropped and skip until + // EOF or the next delimiter + skipUntil(input, c, delimiter); + return 0; + } + + double result = Double.parseDouble(value.toString()); + if (result > 1) { + return 0; + } + return result; + } + + + /** + * Skips all characters until EOF or the specified target is found. Normally + * used to skip invalid input until the next separator. + */ + static SkipResult skipUntil(StringReader input, int c, char target) throws IOException { + while (c != -1 && c != target) { + c = input.read(); + } + if (c == -1) { + return SkipResult.EOF; + } else { + return SkipResult.FOUND; + } + } +} diff --git a/src/main/java/org/olat/core/util/http/SkipResult.java b/src/main/java/org/olat/core/util/http/SkipResult.java new file mode 100644 index 0000000000000000000000000000000000000000..bc1a4d40d4c7290d46f026d4b2eefa6fa00b3d46 --- /dev/null +++ b/src/main/java/org/olat/core/util/http/SkipResult.java @@ -0,0 +1,23 @@ +/* + * 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.olat.core.util.http; + +enum SkipResult { + FOUND, + NOT_FOUND, + EOF +} \ No newline at end of file diff --git a/src/main/java/org/olat/core/util/http/package.html b/src/main/java/org/olat/core/util/http/package.html new file mode 100644 index 0000000000000000000000000000000000000000..cf15556957ba4e26169ee2c0e17eff14216ea097 --- /dev/null +++ b/src/main/java/org/olat/core/util/http/package.html @@ -0,0 +1,6 @@ +<html> +<head></head> +<body> +This Authorization, HttpParser and SkipResult are copy from the Tomcat code. +</body> +</html> \ No newline at end of file diff --git a/src/test/java/org/olat/core/commons/services/webdav/manager/DigestAuthenticationTest.java b/src/test/java/org/olat/core/commons/services/webdav/manager/DigestAuthenticationTest.java new file mode 100644 index 0000000000000000000000000000000000000000..51075c5715970d59f8bc3b7fe2cba4cc043d45ba --- /dev/null +++ b/src/test/java/org/olat/core/commons/services/webdav/manager/DigestAuthenticationTest.java @@ -0,0 +1,64 @@ +/** + * <a href="http://www.openolat.org"> + * OpenOLAT - Online Learning and Training</a><br> + * <p> + * Licensed under the Apache License, Version 2.0 (the "License"); <br> + * you may not use this file except in compliance with the License.<br> + * You may obtain a copy of the License at the + * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a> + * <p> + * Unless required by applicable law or agreed to in writing,<br> + * software distributed under the License is distributed on an "AS IS" BASIS, <br> + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br> + * See the License for the specific language governing permissions and <br> + * limitations under the License. + * <p> + * Initial code contributed and copyrighted by<br> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.core.commons.services.webdav.manager; + +import java.io.IOException; + +import org.junit.Assert; +import org.junit.Test; + +/** + * + * Initial date: 28.10.2015<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public class DigestAuthenticationTest { + + @Test + public void parseDigestAuthentication() { + String request = "Digest username=\"kanu\",realm=\"OLAT WebDAV Access\",nonce=\"dcd98b7102dd2f0e8b11d0f600bfb0c093\",uri=\"/webdav\",cnonce=\"195d0d15b31ee8f0a7f243b9bfcd881d\",nc=00000001,response=\"671742b00fae8d4c8ceb6a5bcf2b36fa\",qop=\"auth\""; + DigestAuthentication auth = DigestAuthentication.parse(request); + Assert.assertEquals("kanu", auth.getUsername()); + Assert.assertEquals("OLAT WebDAV Access", auth.getRealm()); + Assert.assertEquals("dcd98b7102dd2f0e8b11d0f600bfb0c093", auth.getNonce()); + Assert.assertEquals("/webdav", auth.getUri()); + Assert.assertEquals("195d0d15b31ee8f0a7f243b9bfcd881d", auth.getCnonce()); + Assert.assertEquals("00000001", auth.getNc()); + Assert.assertEquals("671742b00fae8d4c8ceb6a5bcf2b36fa", auth.getResponse()); + Assert.assertEquals("auth", auth.getQop()); + } + + @Test + public void parseDigestAuthentication_withSpecialCharacters() throws IOException { + String request = "Digest username=\"kanu\",realm=\"OLAT WebDAV Access\",nonce=\"f1794336f940449a91c0214d39a45538\",uri=\"/olat/webdav/groupfolders/Ajax%20Group/Test%201/Grobplanung,%20rollende%20Planung%20Formular.xls\",cnonce=\"5128af45c016b7590f136fcf1152ebaf\",nc=00000001,response=\"2c56db720b5bb34f1887d4b8f8a41f51\",qop=\"auth\""; + + DigestAuthentication auth = DigestAuthentication.parse(request); + Assert.assertEquals("kanu", auth.getUsername()); + Assert.assertEquals("OLAT WebDAV Access", auth.getRealm()); + Assert.assertEquals("f1794336f940449a91c0214d39a45538", auth.getNonce()); + Assert.assertEquals("/olat/webdav/groupfolders/Ajax%20Group/Test%201/Grobplanung,%20rollende%20Planung%20Formular.xls", auth.getUri()); + Assert.assertEquals("5128af45c016b7590f136fcf1152ebaf", auth.getCnonce()); + Assert.assertEquals("00000001", auth.getNc()); + Assert.assertEquals("2c56db720b5bb34f1887d4b8f8a41f51", auth.getResponse()); + Assert.assertEquals("auth", auth.getQop()); + } + +} diff --git a/src/test/java/org/olat/core/commons/services/webdav/manager/WebDAVManagerTest.java b/src/test/java/org/olat/core/commons/services/webdav/manager/WebDAVManagerTest.java index 97cb76cf780c1250706d93528e6c801d4ebcb03a..3fec61b4cfe43354f7ffc61cfbd266b472681cd4 100644 --- a/src/test/java/org/olat/core/commons/services/webdav/manager/WebDAVManagerTest.java +++ b/src/test/java/org/olat/core/commons/services/webdav/manager/WebDAVManagerTest.java @@ -59,20 +59,6 @@ public class WebDAVManagerTest extends OlatTestCase { @Autowired private WebDAVManagerImpl webDAVManager; - @Test - public void parseDigestAuthentication() { - String request = "username=\"kanu\",realm=\"OLAT WebDAV Access\",nonce=\"dcd98b7102dd2f0e8b11d0f600bfb0c093\",uri=\"/webdav\",cnonce=\"195d0d15b31ee8f0a7f243b9bfcd881d\",nc=00000001,response=\"671742b00fae8d4c8ceb6a5bcf2b36fa\",qop=\"auth\""; - DigestAuthentication auth = DigestAuthentication.parse(request); - Assert.assertEquals("kanu", auth.getUsername()); - Assert.assertEquals("OLAT WebDAV Access", auth.getRealm()); - Assert.assertEquals("dcd98b7102dd2f0e8b11d0f600bfb0c093", auth.getNonce()); - Assert.assertEquals("/webdav", auth.getUri()); - Assert.assertEquals("195d0d15b31ee8f0a7f243b9bfcd881d", auth.getCnonce()); - Assert.assertEquals("00000001", auth.getNc()); - Assert.assertEquals("671742b00fae8d4c8ceb6a5bcf2b36fa", auth.getResponse()); - Assert.assertEquals("auth", auth.getQop()); - } - @Test public void handleBasicAuthentication() { Identity id = JunitTestHelper.createAndPersistIdentityAsUser("dav-user-" + UUID.randomUUID().toString()); diff --git a/src/test/java/org/olat/test/AllTestsJunit4.java b/src/test/java/org/olat/test/AllTestsJunit4.java index 5cf77c00e057cd5e9b8fdeaf5f9923b48507ffa8..deb4aa9f32bc5578526cd625941a44da7e55e0f2 100644 --- a/src/test/java/org/olat/test/AllTestsJunit4.java +++ b/src/test/java/org/olat/test/AllTestsJunit4.java @@ -84,6 +84,7 @@ import org.junit.runners.Suite; org.olat.commons.coordinate.CoordinatorTest.class, org.olat.core.commons.services.help.spi.ConfluenceLinkSPITest.class, org.olat.core.commons.services.webdav.WebDAVCommandsTest.class, + org.olat.core.commons.services.webdav.manager.DigestAuthenticationTest.class, org.olat.core.commons.services.webdav.manager.WebDAVManagerTest.class, org.olat.core.commons.services.webdav.servlets.RequestUtilsTest.class, org.olat.core.commons.services.taskexecutor.PersistentTaskDAOTest.class,