GUACAMOLE-1054: Merge improve Russian translation

diff --git a/extensions/guacamole-auth-radius/src/main/java/org/apache/guacamole/auth/radius/AuthenticationProviderService.java b/extensions/guacamole-auth-radius/src/main/java/org/apache/guacamole/auth/radius/AuthenticationProviderService.java
index fee4357..e5e4f57 100644
--- a/extensions/guacamole-auth-radius/src/main/java/org/apache/guacamole/auth/radius/AuthenticationProviderService.java
+++ b/extensions/guacamole-auth-radius/src/main/java/org/apache/guacamole/auth/radius/AuthenticationProviderService.java
@@ -159,7 +159,9 @@
 
             try {
                 radPack = radiusService.authenticate(credentials.getUsername(),
-                                                credentials.getPassword(), null);
+                                                credentials.getPassword(),
+                                                credentials.getRemoteAddress(),
+                                                null);
             }
             catch (GuacamoleException e) {
                 logger.error("Cannot configure RADIUS server: {}", e.getMessage());
@@ -180,6 +182,7 @@
                 byte[] stateBytes = BaseEncoding.base16().decode(stateString);
                 radPack = radiusService.sendChallengeResponse(credentials.getUsername(),
                                                               challengeResponse,
+                                                              credentials.getRemoteAddress(),
                                                               stateBytes);
             }
             catch (IllegalArgumentException e) {
diff --git a/extensions/guacamole-auth-radius/src/main/java/org/apache/guacamole/auth/radius/RadiusConnectionService.java b/extensions/guacamole-auth-radius/src/main/java/org/apache/guacamole/auth/radius/RadiusConnectionService.java
index c8a21d6..9de19eb 100644
--- a/extensions/guacamole-auth-radius/src/main/java/org/apache/guacamole/auth/radius/RadiusConnectionService.java
+++ b/extensions/guacamole-auth-radius/src/main/java/org/apache/guacamole/auth/radius/RadiusConnectionService.java
@@ -33,6 +33,9 @@
 import org.slf4j.LoggerFactory;
 import net.jradius.client.RadiusClient;
 import net.jradius.dictionary.Attr_CleartextPassword;
+import net.jradius.dictionary.Attr_ClientIPAddress;
+import net.jradius.dictionary.Attr_NASIPAddress;
+import net.jradius.dictionary.Attr_NASPortType;
 import net.jradius.dictionary.Attr_ReplyMessage;
 import net.jradius.dictionary.Attr_State;
 import net.jradius.dictionary.Attr_UserName;
@@ -182,6 +185,10 @@
      * @param secret
      *     The secret, usually a password or challenge response, to send
      *     to authenticate to the RADIUS server.
+     * 
+     * @param clientAddress
+     *     The IP address of the client, if known, which will be set in as
+     *     the RADIUS client address.
      *
      * @param state
      *     The previous state of the RADIUS connection
@@ -192,7 +199,8 @@
      * @throws GuacamoleException
      *     If an error occurs while talking to the server.
      */
-    public RadiusPacket authenticate(String username, String secret, byte[] state)
+    public RadiusPacket authenticate(String username, String secret, 
+                String clientAddress, byte[] state)
             throws GuacamoleException {
 
         // If a username wasn't passed, we quit
@@ -224,6 +232,9 @@
         try {
             AttributeList radAttrs = new AttributeList();
             radAttrs.add(new Attr_UserName(username));
+            radAttrs.add(new Attr_ClientIPAddress(InetAddress.getByName(clientAddress)));
+            radAttrs.add(new Attr_NASIPAddress(InetAddress.getLocalHost()));
+            radAttrs.add(new Attr_NASPortType(Attr_NASPortType.Virtual));
             if (state != null && state.length > 0)
                 radAttrs.add(new Attr_State(state));
             radAttrs.add(new Attr_UserPassword(secret));
@@ -267,6 +278,11 @@
             logger.debug("Unknown RADIUS algorithm.", e);
             return null;
         }
+        catch (UnknownHostException e) {
+            logger.error("Could not resolve address: {}", e.getMessage());
+            logger.debug("Exxception resolving host address.", e);
+            return null;
+        }
         finally {
             radiusClient.close();
         }
@@ -282,6 +298,10 @@
      * @param response
      *     The response phrase to send to the RADIUS server in response to the
      *     challenge previously provided.
+     * 
+     * @param clientAddress
+     *     The IP address of the client, if known, which will be set in as
+     *     the RADIUS client address.
      *
      * @param state
      *     The state data provided by the RADIUS server in order to continue
@@ -295,7 +315,7 @@
      *     If an error is encountered trying to talk to the RADIUS server.
      */
     public RadiusPacket sendChallengeResponse(String username, String response,
-            byte[] state) throws GuacamoleException {
+            String clientAddress, byte[] state) throws GuacamoleException {
 
         if (username == null || username.isEmpty()) {
             logger.error("Challenge/response to RADIUS requires a username.");
@@ -312,7 +332,7 @@
             return null;
         }
 
-        return authenticate(username,response,state);
+        return authenticate(username, response, clientAddress, state);
 
     }
 
diff --git a/guacamole-docker/bin/build-guacamole.sh b/guacamole-docker/bin/build-guacamole.sh
index 88087e5..1b0b0ec 100755
--- a/guacamole-docker/bin/build-guacamole.sh
+++ b/guacamole-docker/bin/build-guacamole.sh
@@ -127,6 +127,7 @@
     cp extensions/guacamole-auth-radius/target/guacamole-auth-radius*.jar "$DESTINATION/radius"
 fi
 
+#
 # Copy OPENID auth extension and schema modifications
 #
 
@@ -136,6 +137,15 @@
 fi
 
 #
+# Copy TOTP auth extension if it was built
+#
+
+if [ -f extensions/guacamole-auth-totp/target/guacamole-auth-totp*.jar ]; then
+    mkdir -p "$DESTINATION/totp"
+    cp extensions/guacamole-auth-totp/target/guacamole-auth-totp*.jar "$DESTINATION/totp"
+fi
+
+#
 # Copy Duo auth extension if it was built
 #
 
diff --git a/guacamole-docker/bin/start.sh b/guacamole-docker/bin/start.sh
index f5367b4..2763096 100755
--- a/guacamole-docker/bin/start.sh
+++ b/guacamole-docker/bin/start.sh
@@ -369,6 +369,7 @@
     set_optional_property "ldap-encryption-method"  "$LDAP_ENCRYPTION_METHOD"
     set_optional_property "ldap-max-search-results" "$LDAP_MAX_SEARCH_RESULTS"
     set_optional_property "ldap-search-bind-dn"     "$LDAP_SEARCH_BIND_DN"
+    set_optional_property "ldap-user-attributes"    "$LDAP_USER_ATTRIBUTES"
 
     set_optional_property           \
         "ldap-search-bind-password" \
@@ -537,6 +538,21 @@
 }
 
 ##
+## Adds properties to guacamole.properties which configure the TOTP two-factor
+## authentication mechanism.
+##
+associate_totp() {
+    # Update config file
+    set_optional_property "totp-issuer"    "$TOTP_ISSUER"
+    set_optional_property "totp-digits"    "$TOTP_DIGITS"
+    set_optional_property "totp-period"    "$TOTP_PERIOD"
+    set_optional_property "totp-mode"      "$TOTP_MODE"
+
+    # Add required .jar files to GUACAMOLE_EXT
+    ln -s /opt/guacamole/totp/guacamole-auth-*.jar   "$GUACAMOLE_EXT"
+}
+
+##
 ## Adds properties to guacamole.properties which configure the Duo two-factor
 ## authentication service. Checks to see if all variables are defined and makes sure
 ## DUO_APPLICATION_KEY is >= 40 characters.
@@ -707,6 +723,11 @@
     exit 1;
 fi
 
+# Use TOTP if specified.
+if [ "$TOTP_ENABLED" = "true" ]; then
+    associate_totp
+fi
+
 # Use Duo if specified.
 if [ -n "$DUO_API_HOSTNAME" ]; then
     associate_duo