2017-01-16 20:59:50 +01:00
/ * Copyright ( c ) Citrix Systems , Inc .
2013-06-24 13:41:48 +02:00
* All rights reserved .
*
* Redistribution and use in source and binary forms ,
* with or without modification , are permitted provided
* that the following conditions are met :
*
* * Redistributions of source code must retain the above
* copyright notice , this list of conditions and the
* following disclaimer .
* * Redistributions in binary form must reproduce the above
* copyright notice , this list of conditions and the
* following disclaimer in the documentation and / or other
* materials provided with the distribution .
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES ,
* INCLUDING , BUT NOT LIMITED TO , THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED . IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT , INDIRECT , INCIDENTAL ,
* SPECIAL , EXEMPLARY , OR CONSEQUENTIAL DAMAGES ( INCLUDING ,
* BUT NOT LIMITED TO , PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES ; LOSS OF USE , DATA , OR PROFITS ; OR BUSINESS
* INTERRUPTION ) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY ,
* WHETHER IN CONTRACT , STRICT LIABILITY , OR TORT ( INCLUDING
* NEGLIGENCE OR OTHERWISE ) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE , EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE .
* /
using System ;
using System.IO ;
using System.Text ;
using CookComputing.XmlRpc ;
using XenAdmin ;
using XenAdmin.Network ;
2017-09-13 18:14:07 +02:00
using Newtonsoft.Json.Linq ;
2013-06-24 13:41:48 +02:00
namespace XenAPI
{
public partial class Session
{
private static readonly log4net . ILog log = log4net . LogManager . GetLogger ( System . Reflection . MethodBase . GetCurrentMethod ( ) . DeclaringType ) ;
public bool IsElevatedSession = false ;
private Session ( int timeout , IXenConnection connection , string url )
2017-09-13 18:14:07 +02:00
: this ( CreateProxy ( url , timeout ) , connection )
2013-06-24 13:41:48 +02:00
{
2017-09-13 18:14:07 +02:00
proxy . RequestEvent + = LogRequest ;
proxy . ResponseEvent + = LogResponse ;
2013-06-24 13:41:48 +02:00
}
public Session ( Proxy proxy , IXenConnection connection )
{
Connection = connection ;
2017-09-13 18:14:07 +02:00
this . proxy = proxy ;
2013-06-24 13:41:48 +02:00
}
2017-09-13 18:14:07 +02:00
public Session ( int timeout , IXenConnection connection , string host , int port )
: this ( timeout , connection , GetUrl ( host , port ) )
2013-06-24 13:41:48 +02:00
{
}
2017-09-13 18:14:07 +02:00
public Session ( Session session , Proxy proxy , IXenConnection connection )
: this ( proxy , connection )
2013-06-24 13:41:48 +02:00
{
2017-09-13 18:14:07 +02:00
InitAD ( session ) ;
2013-06-24 13:41:48 +02:00
}
/// <summary>
/// Create a new Session instance, using the given instance and timeout. The connection details and Xen-API session handle will be
/// copied from the given instance, but a new connection will be created. Use this if you want a duplicate connection to a host,
/// for example when you need to cancel an operation that is blocking the primary connection.
/// </summary>
public Session ( Session session , IXenConnection connection , int timeout )
{
2017-09-13 18:14:07 +02:00
if ( session . JsonRpcClient ! = null )
{
JsonRpcClient = new JsonRpcClient ( session . Url ) { JsonRpcVersion = session . JsonRpcClient . JsonRpcVersion } ;
JsonRpcClient . RequestEvent + = LogJsonRequest ;
}
else
{
proxy = CreateProxy ( session . Url , timeout ) ;
proxy . RequestEvent + = LogRequest ;
proxy . ResponseEvent + = LogResponse ;
}
Connection = connection ;
2013-06-24 13:41:48 +02:00
InitAD ( session ) ;
}
private void InitAD ( Session session )
{
2018-02-12 12:54:27 +01:00
opaque_ref = session . opaque_ref ;
2013-06-24 13:41:48 +02:00
APIVersion = session . APIVersion ;
_userSid = session . UserSid ;
_subject = session . Subject ;
_isLocalSuperuser = session . IsLocalSuperuser ;
roles = session . Roles ;
permissions = session . Permissions ;
}
2017-09-13 18:14:07 +02:00
private static Proxy CreateProxy ( string url , int timeout )
{
var xmlrpcProxy = XmlRpcProxyGen . Create < Proxy > ( ) ;
xmlrpcProxy . Url = url ;
xmlrpcProxy . NonStandard = XmlRpcNonStandard . All ;
xmlrpcProxy . Timeout = timeout ;
xmlrpcProxy . UseIndentation = false ;
xmlrpcProxy . UserAgent = UserAgent ;
xmlrpcProxy . KeepAlive = true ;
xmlrpcProxy . Proxy = Proxy ;
// reverted because of CA-137829/CA-137959: _proxy.ConnectionGroupName = Guid.NewGuid().ToString(); // this will force the Session onto a different set of TCP streams (see CA-108676)
return xmlrpcProxy ;
}
2013-06-24 13:41:48 +02:00
/// <summary>
/// When the CacheWarming flag is set, we output logging at Debug rather than Info level.
/// This means that we don't spam the logs when the application starts.
/// </summary>
private bool _cacheWarming = false ;
public bool CacheWarming
{
get { return _cacheWarming ; }
set { _cacheWarming = value ; }
}
2018-01-24 16:45:06 +01:00
/// <summary>
/// Do not log while downloading objects;
/// also exclude calls occurring frequently, we don't need to know about them
/// </summary>
private bool CanLogCall ( string call )
{
return CacheWarming | |
call = = "event.next" | | call = = "event.from" | | call = = "host.get_servertime" | |
call . StartsWith ( "task.get_" ) ;
}
2017-09-13 18:14:07 +02:00
private void LogJsonRequest ( string json )
{
2018-01-24 16:45:06 +01:00
#if DEBUG
2017-12-21 15:18:09 +01:00
string methodName = "" ;
string parameters = "" ;
2017-09-13 18:14:07 +02:00
try
{
JObject obj = JObject . Parse ( json ) ;
methodName = obj . Property ( "method" ) . Value . ToString ( ) ;
parameters = obj . Property ( "params" ) . Value . ToString ( ) ;
}
catch
{
2017-12-21 15:18:09 +01:00
//ignore
2017-09-13 18:14:07 +02:00
}
// only log the full parameters at Debug level because it may contain sensitive data
2018-01-24 16:45:06 +01:00
if ( CanLogCall ( methodName ) )
2017-09-13 18:14:07 +02:00
log . DebugFormat ( "Invoking JSON-RPC method '{0}' with params: {1}" , methodName , parameters ) ;
else
log . InfoFormat ( "Invoking JSON-RPC method '{0}'" , methodName ) ;
2018-01-24 16:45:06 +01:00
#else
string methodName = json ;
if ( CanLogCall ( methodName ) )
log . DebugFormat ( "Invoking JSON-RPC method '{0}'" , methodName ) ;
else
log . InfoFormat ( "Invoking JSON-RPC method '{0}'" , methodName ) ;
#endif
2017-09-13 18:14:07 +02:00
}
2013-06-24 13:41:48 +02:00
private void LogRequest ( object o , XmlRpcRequestEventArgs args )
{
string xml = DumpStream ( args . RequestStream , String . Empty ) ;
// Find the method name within the XML
string methodName = "" ;
int methodNameStart = xml . IndexOf ( "<methodName>" ) ;
if ( methodNameStart > = 0 )
{
2017-09-13 17:26:41 +02:00
methodNameStart + = 12 ; // skip past "<methodName>"
2013-06-24 13:41:48 +02:00
int methodNameEnd = xml . IndexOf ( '<' , methodNameStart ) ;
if ( methodNameEnd > methodNameStart )
methodName = xml . Substring ( methodNameStart , methodNameEnd - methodNameStart ) ;
}
2017-09-13 17:26:41 +02:00
// do not log while downloading objects
// also exclude calls occurring frequently; we don't need to know about them;
// only log the full XML at Debug level because it may have sensitive data in: CA-80174
2013-06-24 13:41:48 +02:00
2018-01-24 16:45:06 +01:00
if ( CanLogCall ( methodName ) )
2017-09-13 17:26:41 +02:00
{
log . DebugFormat ( "Invoking XML-RPC method {0}: {1}" , methodName , xml ) ;
}
2013-06-24 13:41:48 +02:00
else
2017-09-13 17:26:41 +02:00
{
log . InfoFormat ( "Invoking XML-RPC method {0}" , methodName ) ;
}
2013-06-24 13:41:48 +02:00
}
private void LogResponse ( object o , XmlRpcResponseEventArgs args )
{
if ( log . IsDebugEnabled )
2017-09-13 17:26:41 +02:00
log . DebugFormat ( DumpStream ( args . ResponseStream , "XML-RPC response: " ) ) ;
2013-06-24 13:41:48 +02:00
}
private string DumpStream ( Stream s , string header )
{
try
{
StringBuilder stringBuilder = new StringBuilder ( header ) ;
using ( TextReader r = new StreamReader ( s ) )
{
string l ;
while ( ( l = r . ReadLine ( ) ) ! = null )
stringBuilder . Append ( l ) ;
}
return stringBuilder . ToString ( ) ;
}
catch ( OutOfMemoryException ex )
{
2017-09-13 17:26:41 +02:00
log . DebugFormat ( "Session ran out of memory while trying to log the XML response stream: {0}" , ex . Message ) ;
2013-06-24 13:41:48 +02:00
return String . Empty ;
}
}
/// <summary>
/// The i18n'd string for the 'Logged in as:' username (AD or local root).
/// </summary>
2017-09-03 04:33:29 +02:00
public string UserFriendlyName ( )
2013-06-24 13:41:48 +02:00
{
2017-09-03 04:33:29 +02:00
if ( IsLocalSuperuser )
return Messages . AD_LOCAL_ROOT_ACCOUNT ;
2013-06-24 13:41:48 +02:00
2017-09-03 04:33:29 +02:00
if ( ! string . IsNullOrEmpty ( CurrentUserDetails . UserDisplayName ) )
return CurrentUserDetails . UserDisplayName . Ellipsise ( 50 ) ;
2013-06-24 13:41:48 +02:00
2017-09-03 04:33:29 +02:00
if ( ! string . IsNullOrEmpty ( CurrentUserDetails . UserName ) )
return CurrentUserDetails . UserName . Ellipsise ( 50 ) ;
2013-06-24 13:41:48 +02:00
2017-09-03 04:33:29 +02:00
return Messages . UNKNOWN_AD_USER ;
2013-06-24 13:41:48 +02:00
}
/// <summary>
/// Useful as a unique name for logging purposes
/// </summary>
2017-09-03 04:33:29 +02:00
public string UserLogName ( )
2013-06-24 13:41:48 +02:00
{
2017-09-03 04:33:29 +02:00
if ( IsLocalSuperuser )
return Messages . AD_LOCAL_ROOT_ACCOUNT ;
2013-06-24 13:41:48 +02:00
2017-09-03 04:33:29 +02:00
if ( ! string . IsNullOrEmpty ( CurrentUserDetails . UserName ) )
return CurrentUserDetails . UserName ;
2013-06-24 13:41:48 +02:00
2017-09-03 04:33:29 +02:00
return UserSid ;
2013-06-24 13:41:48 +02:00
}
/// <summary>
/// This gives either a friendly csv list of the sessions roles or a friendly string for Local root account.
/// If Pre MR gives Pool Admin for AD users.
/// </summary>
2017-09-03 04:33:29 +02:00
public string FriendlyRoleDescription ( )
2013-06-24 13:41:48 +02:00
{
2017-09-03 04:33:29 +02:00
if ( IsLocalSuperuser | | XenAdmin . Core . Helpers . GetMaster ( Connection ) . external_auth_type ! = Auth . AUTH_TYPE_AD )
return Messages . AD_LOCAL_ROOT_ACCOUNT ;
2013-06-24 13:41:48 +02:00
2017-09-03 04:33:29 +02:00
return Role . FriendlyCSVRoleList ( Roles ) ;
2013-06-24 13:41:48 +02:00
}
/// <summary>
/// This gives either a friendly string for the dominant role on the session or a friendly string for Local root account.
/// If Pre MR gives Pool Admin for AD users.
/// </summary>
2017-09-03 04:33:29 +02:00
public string FriendlySingleRoleDescription ( )
2013-06-24 13:41:48 +02:00
{
2017-09-03 04:33:29 +02:00
if ( IsLocalSuperuser | | XenAdmin . Core . Helpers . GetMaster ( Connection ) . external_auth_type ! = Auth . AUTH_TYPE_AD )
return Messages . AD_LOCAL_ROOT_ACCOUNT ;
2013-06-24 13:41:48 +02:00
2017-09-03 04:33:29 +02:00
//Sort roles from highest to lowest
roles . Sort ( ( r1 , r2 ) = > { return r2 . CompareTo ( r1 ) ; } ) ;
//Take the highest role
return roles [ 0 ] . FriendlyName ( ) ;
2013-06-24 13:41:48 +02:00
}
}
}