View
6
Download
0
Category
Preview:
Citation preview
1
MyFirst IdP
EuroCAMP Training
This work is licensed under a Creative Commons
Attribution‐ShareAlike 3.0 Unported License.
Acknowledgements
• Portions of this training course taken from:– SWITCHaai
– simpleSAMLphp website
– EduGate Federation
– K.U.Leuven Shibboleth Materials
2
Pre‐requisites
• A training VM from Disc or Web that has been i iti ll tinitially setup.
• This image has simpleSAMLphp, Shibboleth SP and other utilities included.
What’s on the VM?
• TurnKey Linux LAMP Stackhtt // t k li /l t k– http://www.turnkeylinux.org/lampstack
– Apache HTTPd Web Server
– MySQL Database
– PHP 5.3
• simpleSAMLphp + requirements– http://simplesamlphp.org/docs/1.8/simplesamlphp‐install
• OpenLDAP Directory
• Shibboleth Service Provider– Daemon + mod_shib for Apache
• Dynamic DNS Client & Configuration
3
simpleSAMLphp vs ShibbolethsimpleSAMLphp Shibboleth IdP Shibboleth SP
SAML1.1 (Shib Profile) ~ X X
SAML2 0 (saml2int) X X XSAML2.0 (saml2int) X X X
Identity Provider (IdP) X X ‐
Service Provider (SP) X ‐ X
Bridge (IdP<‐>SP) X ‐ ‐
OAuth/OpenID X ‐ ‐
Discovery Service X ‐ ‐
Latest Version 1.8 2.2 2.4
Programming Lang. PHP Java Servlet C
Primary Developer UNINETT Internet2 Internet2
• simpleSAMLphp doesn’t support the IdP Artifact• Discovery Service /DS is a separate Java Servlet • simpleSAMLphp can bridge OAuth/OpenID to SAML
Login & Set up simpleSAMLphp
4
Basic simpleSAMLphp setup
• Copy the default configuration files:cd /var/simplesamlphp/cd /var/simplesamlphp/cp -r config-templates/* config/cp -r metadata-templates/* metadata/
• simpleSAMLphp installed using Subversioncd /var/svn checkout http://simplesamlphp.googlecode.com/svn/trunk/
cd /var/simplesamlphp/cp -r config-templates/* config/cp -r metadata-templates/* metadata/
simplesamlphp
• Subversion ‘svn’ is a version control systemcd /var/simplesamlphp/svn update update to latest versionsvn update –r XXXX goto revision, default HEAD
http://svnbook.red‐bean.com/
Your simpleSAML page is live!
5
The IdP isn’t setup yet…
Explore simpleSAMLphp…
6
Default password ‘123’
Enabling SAML 2.0 IdP
• We need to enable SAML2.0 IdP!
• simpleSAMLPphp configuration located at:/var/simplesamlphp/config/
• Two major configuration files:config.phpauthsources.php
• Take a look at config php• Take a look at config.phpcd /var/simplesamlphp/config/more config.php
http://simplesamlphp.org/docs/1.8/simplesamlphp-install #section_7
cd /var/simplesamlphp/config/more config.php
7
3 ways to edit files
• Two via the command line terminal:cd /var/simplesamlphp/config/cd /var/simplesamlphp/config/
– vi – the visual editorvi config.php
– pico/nanopico config.php
easier to use that vi if you’ve never used vi
• Web Based Simple Editor
Essential File Editing CommandsEditor Nano VIMOpen file $ nano file.xml $ vim file.xml
Save file <ctrl>-o <esc>, :w
Save and exit <ctrl>-x <esc>, :wq<esc>, ZZ
Search string <ctrl>-w, string <esc>, /string
Go to line <ctrl>--, number <esc>, number,number
, , ,<shift>-G
Pro and Cons + Easy- Few features
+ Powerful- A bit “weird” to use
http://www.switch.ch/aai/support/presentations/installfest‐2009/ShibInstallFest‐Tipps‐and‐Tricks.ppt
8
Web Interface for editing…
Web Interface for editing…
• … for file browser.
• Edit to launch editor.
9
• Basic textditiediting.
• Click to ‘Save’
Remember to change…
• Enable IdP:'enable saml20 idp' > true' bl l20 id ' t'enable.saml20-idp' => true,
• Generate Random Bytes:'auth.adminpassword' => 'your_new_password’,
– or type random characters.
• Update Secret Salt:
'enable.saml20-idp' => true,
tr -c -d '0123456789abcdefghijklmnopqrstuvwxyz’ \</dev/urandom | dd bs=32 count=1 2>/dev/null;echo
'auth.adminpassword' => 'your new password’,
• Admin Password & Contact Details:'auth.adminpassword' => 'your_new_password’,
'secretsalt' => 'randombytesinsertedhere', # or type junk!
'auth.adminpassword' => 'your_new_password','technicalcontact_name' => 'My Name','technicalcontact_email' => 'my.name@inst.federated.now',
http://simplesamlphp.org/docs/1.8/simplesamlphp-install#section_7
10
How do you want to login?
• Pick an authentication source– X509 Certificate, RADIUS, OpenID, YubiKey, Facebook, Twitter, MySpace, LinkedIn, Windows Live ID.
– …or write your own.
• We will look at 3– Configuration File with Username/Password
– SQL Database
– LDAP Directory
11
Simple Username/Password Auth
• Uses the exampleauth module – enable it!t h d l / l th/ bltouch modules/exampleauth/enable
Some basic test accounts…
– Edit config/authsources.php
E bl l / /– Enable example-userpass – remove /* *//*'example-userpass' => array(
'exampleauth:UserPass','student:studentpass' => array(
'uid' => array('test'),'eduPersonAffiliation' => array('member', 'student'),
),
– Add your own account – watch out for ,
'employee:employeepass' => array('uid' => array('employee'),'eduPersonAffiliation' => array('member', 'employee'),
),),*/
12
Add an account'example-userpass' => array(
'exampleauth:UserPass','student:studentpass' => array(
'uid' => array('test'),uid > array( test ),'eduPersonAffiliation' => array('member', 'student'),
),'employee:employeepass' => array(
'uid' => array('employee'),'eduPersonAffiliation' => array('member', 'employee'),
),'username:password' => array(
'uid' => array('username'),
• Pick a username and password.
'eduPersonAffiliation' => array('member', 'faculty'),),
),
Add additional attributes
'username:password' => array('uid' => array('username'),' d P Affili ti ' > (' b ' 'f lt ')
• Logout and Login in to see your attributes.
'eduPersonAffiliation' => array('member', 'faculty'),'cn' => array('My Name'),'postalCode' => array('1017 AW'),'telephoneNumber' => array('+31205304488'),
),),
• For an extensive list of attribute look at:more attributemap/name2oid.php
13
How to really test this IdP?
• Can’t test generated attributes via authsource
• Setup additional hostnames:
•
• Refresh Dynamic DNS and wait
echo 'idpXX-wsX.lab.iamfederated.org' >> /etc/ddclient.confecho 'spXX-wsX.lab.iamfederated.org' >> /etc/ddclient.conf
more /etc/ddclient.conf
• Swap the IdPs metadata with our SPs!
/etc/init.d/ddclient restartgrep ddclient /var/log/syslog
Find your IdPs Metadata
• Click “Show metadata” under the IdP entry
14
Copy the PHP version of Metadata
• Add to metadata/saml20-idp-remote.php$metadata['https://host12-ws3.lab.iamfederated.org/simplesaml/saml2/idp/metadata.php'] = array (
'metadata-set' => 'saml20-idp-remote','entityid' => 'https://host12-
ws3.lab.iamfederated.org/simplesaml/saml2/idp/metadata.php','SingleSignOnService' => 'https://host12-
ws3.lab.iamfederated.org/simplesaml/saml2/idp/SSOService.php'
);
,'SingleLogoutService' => 'https://host12-
ws3.lab.iamfederated.org/simplesaml/saml2/idp/SingleLogoutService.php',
'certData' => 'MIICgTCCAeoCCQCbOlrWDdX7FTANBgkqhkiG9w0BA…','NameIDFormat' => 'urn:oasis:names:tc:SAML:2.0:nameid-
format:transient',);
Login from your SP
• Visit https://spXX‐wsX.lab.iamfederated.org/simplesaml/
• Select ‘default‐sp’
15
Error?
Your IdP needs know your SP
• Visit https://spXX‐wsX.lab.iamfederated.org/simplesaml/
16
Your IdP needs know your SP
• Copy the PHP metadata.
• Add to metadata/saml20-sp-remote.php$metadata['https://sp12-ws3.lab.iamfederated.org/simplesaml/module.php/saml/sp/metadata.php/default-sp'] = array (
'AssertionConsumerService' => 'https://sp12-ws3.lab.iamfederated.org/simplesaml/module.php/saml/sp/saml2-acs.php/default-sp',
'SingleLogoutService' => 'https://sp12-
• Try logging in again at http://spXX‐wsX…);
SingleLogoutService => https://sp12-ws3.lab.iamfederated.org/simplesaml/module.php/saml/sp/saml2-logout.php/default-sp',);
Copy & Paste Error? …or not!
17
Spot the difference
• Four differences between left & right.
• HTTP vs HTTPS changes the dynamic entityID.
You might have seen this warning…
18
Two solutions to fix this
• Force HTTPS on your website– Apache Configuration for SSL/TLS
– Redirecting HTTP HTTPS
– HTTP Strict Transport Security (HSTS)
• Hardwire the entityID– Can be configured statically rather than dynamic– Can be configured statically rather than dynamic.
– Best practice is to make your metadata accessible from your entityID URI, so that it is also a URL.
• Can use “Redirect” in Apache config to achieve this.
HTTP ‐> HTTPS Redirect
• Add to HTTP VHOST configuration:vi /etc/apache2/sites enabled/000 defaultvi /etc/apache2/sites-enabled/000-default<VirtualHost *:80>…<IfModule mod_rewrite.c>
RewriteEngine OnRewriteCond %{HTTPS} offRewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI}
</IfModule></VirtualHost>
• Uses a Rewrite Rule to force site to HTTPS
• Enable rewrite & headers and restart Apachea2enmod rewrite headers/etc/init.d/apache2 restart
/ tua ost
19
Test HTTPS Redirect
• Visit your hosts:– http://host… ‐> https://host…
– http://idp… ‐> https://idp…
– http://sp… ‐> https://sp…
• Make the redirect permanent by adding HSTS to your HTTPS VHOST configuration:to your HTTPS VHOST configuration:
– 15768000 is 6 months – try 86400 for 1 day
Header add Strict-Transport-Security "max-age=15768000"
Google Chrome using SSL
20
Mozilla Firefox using SSL
Safari using SSL
21
Hardwiring the entityID
• Dynamically generated entityID format:– IdP:
• http{s}://{hostname}/{path}/saml2/idp/metadata.php
– SP:• http{s}://{hostname}/{path}/module.php/sp/metadata.
/var/simplesamlphp/metadata/saml20-idp-hosted.php$metadata['__DYNAMIC:1__'] = array();
p{ } //{ }/{p }/ p p/ p/php/{authsource}
/var/simplesamlphp/config/authsources.php'default-sp' => array(
'saml:SP','entityID' => NULL,
// https://{hostname}/sp is a suitable entityID.
Check your metadata!
• Make sure HTTPS is used in:– metadata/saml20-idp-remote.php– metadata/saml20-sp-remote.php
• Remember we were trying to login to an SP!– http://spXX‐wsX.lab… the URL should adjust.
– and log in!– …and log in!
• There are some addition attributes we can generate.
22
Logging
• By default simpleSAML logs to syslog: 'logging level' > LOG NOTICE'logging.level' => LOG NOTICE,'logging.handler' => 'syslog', 'logging.processname' => ’simplesamlphp',
tail –f /var/log/syslog | grep ‘simplesaml’
• I prefer logging to a file:
tail –f /var/log/syslog | grep ‘simplesaml’
'logging.level' => LOG_DEBUG,'logging.handler' => 'file’
cd /var/simplesamlphpchown -R www-data:www-data logchmod -R g+w log
cd /var/simplesamlphpchown -R www-data:www-data logchmod -R g+w log
tail –f /var/simplesaml/log/simplesaml.log
Generate TargetedID
• Enable core:TargetedID in config/config.php/* E bl th th filt b l t t ti ll
• In metadata/saml20-idp-hosted.php add
/* Enable the authproc filter below to automatically generated eduPersonTargetedID.*/20 => 'core:TargetedID',*/
'userid.attribute' => 'uid’,
• Alternatively configure w/attributename20 => 'core:TargetedID',20 => array(
'class' => 'core:TargetedID', 'attributename' => 'uid’
),
23
core:AttributeAdd
• Ideal for static attributes that are for all users10 => array(
'class' => 'core:AttributeAdd','o' => 'yourorg','l' => 'Istanbul','ou' => 'ITS','schacHomeOrganization' => 'yourorg.ac.bv',
),
• Replace attribute rather than merge10 => array(
'class' => 'core:AttributeAdd','%replace','eduPersonAffiliation' => array('student', 'members'),
),
core:ScopeAttribute
• Add scope to Affiliations10 (
• Manufacture eppn (eduPersonPrinipalName) f th tt ib t
10 => array( 'class' => 'core:ScopeAttribute', 'scopeAttribute' => 'eduPersonPrincipalName',
'sourceAttribute' => 'eduPersonAffiliation', 'targetAttribute' => 'eduPersonScopedAffiliation',
),
from other attributes10 => array(
'class' => 'core:ScopeAttribute', 'scopeAttribute' => 'schacHomeOrganization',
'sourceAttribute' => 'uid','targetAttribute' => 'eduPersonPrincipalName',
),
24
core:AttributeMap
• Rename or Duplicate Attributes50 (50 => array(
'class' => 'core:AttributeMap', 'mail' => 'email', 'uid' => 'user' 'cn' => array('name', 'displayName'),
),60 => array(
'class' => 'core:AttributeMap', 'name2oid',
• Check out the other Auth Proc filters and add some to your IdP:
• http://simplesamlphp.org/docs/1.8/simplesamlphp‐authproc#section_2
name2oid , ),
More common to map to OID
• Update your metadata/saml20-idp-hosted.phpi
Vi i i
'AttributeNameFormat' => 'urn:oasis:names:tc:SAML:2.0:attrname-format:uri', 'authproc' => array(
// Convert LDAP names to oids. 100 => array(
'class' => 'core:AttributeMap', 'name2oid’),
),
• View mappings in attributemap/name2oid.php
'audio' => 'urn:oid:0.9.2342.19200300.100.1.55’,
'aRecord' => 'urn:oid:0.9.2342.19200300.100.1.26','aliasedEntryName' => 'urn:oid:2.5.4.1','aliasedObjectName' => 'urn:oid:2.5.4.1','associatedDomain' =>
'urn:oid:0.9.2342.19200300.100.1.37','associatedName' => 'urn:oid:0.9.2342.19200300.100.1.38','audio' => 'urn:oid:0.9.2342.19200300.100.1.55’,
25
SAML2 Interoperability Profile
• http://saml2int.org for more information.
Using a DB for Auth & Attributes
• The sqlauth:SQL module is enabled by default
• Activate setup in config/authsources.php/*'example-sql' => array(
'sqlauth:SQL','dsn' => 'mysql:host=localhost;dbname=simplesaml','username' => 'simplesaml','password' => 'secretpassword',
– Remove the double quotes (“”) from the query
'query' => 'SELECT "username", "name", "email" FROM "users" WHERE "username" = :username AND "password" = :password',),*/
26
Using a DB for Auth & Attributes
• More complex query:' l l ' > ('sql-exampleorg-groups' => array(
'sqlauth:SQL','dsn' => 'mysql:host=localhost;dbname=simplesaml','username' => 'simplesaml','password' => 'secretpassword','query' => 'SELECT users.username, name, email,
groupname AS groups FROM users LEFT JOIN usergroups ON users.username=usergroups.username WHERE users.username = :username AND password = :password',
• Or a really simple query (bonus attributes):
:username AND password :password ,),
'query' => 'SELECT * FROM users WHERE username = :username AND password = :password',
Basic Test AccountsUsername Password Namestud1 pass1 Juan Student
staff2 pass2 Twee Staff
teach3 pass3 Trio Teacher
alum4 pass4 Quart Alumni
• Use mysql to investigate the datamysql –u root –p simplesamlEnter password:mysql> show tables;mysql> explain users;mysql> select * from users;
27
Update your IdP
• Edit metadata/saml20‐idp‐hosted.php// ' th' > ' l '
• Now visit your SP and test…
// 'auth' => 'example-userpass','auth' => 'example-sql',
• Check the logs for any problems.
Using LDAP for Auth & Attributes
• The ldap:LDAP module is enabled by default
• Activate setup in config/authsources.php/*'example-ldap' => array(
'ldap:LDAP','hostname' => 'localhost',// all attributes are fetched.'attributes' => NULL,'dnpattern' =>
'uid=%username%,ou=people,dc=example,dc=org','search.enable' => FALSE,
…),*/
28
Update your IdP
• Edit metadata/saml20‐idp‐hosted.php// ' th' > ' l '
• Now visit your SP and test…
// 'auth' => 'example-userpass','auth' => 'example-sql',
• Check the logs for any problems.
• Can you use every test account?
Specifically request attributes
• DN isn’t returned by default.'example-ldap' => array(
'ldap:LDAP','hostname' => 'localhost',// all attributes are fetched.'attributes' => NULL,'attributes' => array('uid','sn','cn','entryDN',
'objectClass'),'dnpattern' =>
'uid=%username%,ou=people,dc=example,dc=org','search.enable' => FALSE,
…),
29
Enable searching the LDAP tree
'example-ldap' => array('ldap:LDAP',ldap:LDAP ,'hostname' => 'localhost',// all attributes are fetched.'attributes' => array('uid','sn','cn','entryDN',
'objectClass'),'dnpattern' =>
'uid=%username%,ou=people,dc=example,dc=org','search.enable' => FALSETRUE,'search.base' => 'ou=people,dc=example,dc=org',
• Now stud1 & alum4 work.
…),
Auth Proc for Affiliation
• Map uid=stud1,ou=students,dc=example,dc=org to an affiliation.
10 => array('class' => 'core:AttributeAlter', 'subject' => 'entryDN','pattern' => '/ou=people/','replacement' => 'staff','target' => 'eduPersonPrimaryAffiliation',
),11 => array(
'class' => 'core:AttributeAlter', 'subject' => 'entryDN', 'pattern' => ’/ou=students/','replacement' => 'student','target' => 'eduPersonPrimaryAffiliation',
),
30
But LDAP has less attributes…
• LDAP is our password trust store.
• MySQL is a data repository.
• Would be great if we could have both!
Multiple Attribute Sources
• confia AttributeCollector supports:– LDAP
– SQL
• Install using (but it’s already installed on VM):cd /var/simplesamlphp/modulessvn checkout \https://forja.rediris.es/svn/confia/attributecollector/trunk/
• Thanks to confia– http://confia.aupa.info/
https://forja.rediris.es/svn/confia/attributecollector/trunk/ attributecollector
31
Set as an Auth Proc for the IdP
• Configure in metadata/saml20-idp-hosted.php'authproc' => array(
10 => array('existing' => 'preserve','class' => 'attributecollector:AttributeCollector','uidfield' => 'uid','collector' => array(
'class' => 'attributecollector:SQLCollector','dsn' => 'mysql:host=localhost;dbname=simplesaml',' ' ' i l l''username' => 'simplesaml','password' => 'secretpassword','query' => 'SELECT * from users where
username=:uidfield',),
),),
Certificates & SSL
• HTTPS Certificates– TERENA Certificate Service (TCS) Certificates
• *.lab.iamfederated.org
– Located in:/etc/ssl/certs/cert.pem (crt + key)
• SAML Signing Certificatesg g
• These are different!
32
Certificates & SSL
• Generated with:l k 2048 509 d 3652 d \
• simpleSAMLphp uses keys for:
openssl req -newkey rsa:2048 -new -x509 -days 3652 -nodes \-out example.org.crt -keyout example.org.pem
config/config.php: (metadata signing)'metadata.sign.enable' => FALSE,'metadata.sign.privatekey' => NULL,'metadata.sign.certificate' => NULL,
metadata/saml20-idp-hosted.php:'privatekey' => 'server.pem','certificate' => 'server.crt',
config/authsource: (signing messages of SP)'redirect.sign' => true,'privatekey' => 'server.pem’,
Testing your SSL certificate
• Visit https://www.ssllabs.com/ssldb/
33
Testing your SSL certificate
• SSL Labs Report will detail– Certificate change wrong/incorrect/incomplete
– Certificate root valid and in browsers
– Protocols supported by your webserver
– Cipher suites available
– Renegotiation Secure/InsecureRenegotiation Secure/Insecure• Requires OpenSSL >= 0.9.8m
• This VM has OpenSSL 0.9.8k :‐(
• Won’t work behind NAT but test it on production!
Consent Module
• See what attributes your sending before you d !do!
• Enabled by default – configure in config.php/** Consent module is enabled (with no permanent storage, using cookies).*/
90 => array('class' => 'consent:Consent', 'store' => 'consent:Cookie', 'focus' => 'yes', 'checked' => TRUE
),*/
34
Translating simpleSAMLphp
• World doesn’t just speak English!
• Luckily neither do the simpleSAMLphp devs!
• Currently available in:– English, Bokmål, Nynorsk, Sámegiella, Dansk, Deutsch, Español, Svenska, Suomeksi, Français, Italiano, Nederlands, Luxembourgish, Czech,Italiano, Nederlands, Luxembourgish, Czech, Slovenščina, Hrvatski, Magyar, Język polski, Português, Português brasileiro, Türkçe, 日本語, 中文, ελληνικά, Lietuvių kalba, Åarjelh‐saemiengiele, русский язык
Translating simpleSAMLphp
• Visit http://translation.rnd.feide.no/
• Login with your OpenIdP Account.
• Start translating…
35
Translating simpleSAMLphp
• If you language isn’t there – sign up for the i l SAML h t l ti ili li tsimpleSAMLphp translation mailing list:
• http://simplesamlphp.org/lists
• Request that your language is added to the translation portal.
• Once you’ve completed translating someOnce you ve completed translating some modules request publishing of the translation.
• More info at:– http://simplesamlphp.org/docs/1.8/simplesamlphp‐translation
Update published translations
• Once published – you can download updates i t llincrementally.
• Or update all translation files:
cd /var/simplesamlbin/translation.php pull./modules/core/dictionaries/frontpage.translation.json
cd /var/simplesaml
– The ‘\’ continues the input on the next line.
cd /var/simplesamlfind . -name '*.translation.json' | xargs -n 1 \bin/translation.php pull
36
This training course...
• Participants from:– Azerbaijan, Armenia, Serbia, Turkey, FYR Macedonia, Moldova, Georgia, Belarus, Lithuania, Estonia
• Spoken languages include:• 0% ‐ Azeri (az/azj/azb), Belarusian (be), Serbian (sr/srp), Armenian (hy/arm), Macedonian (mk), Albanian (sq), Romanian (ro), Moldovan, Georgian (ka)
• Russian (12.44%), Turkish (69.40%), Estonian (94.78%), Lithuanian (97.26%), Croatian (99.25%)
• 402 phrases to translate! As short as 1 word.
Now with Right‐to‐Left (RTL)
37
100% Hebrew Translation
• Translation completed in 1 week.
Specifying Language Options/** Languages available, RTL languages, and default language*/'language available' => array('en' 'no' 'nn' 'se'
• Adjust the visible languages on your home
language.available => array( en , no , nn , se , 'da', 'de', 'sv', 'fi', 'es', 'fr', 'it', 'nl', 'lb', 'cs', 'sl', 'lt', 'hr', 'hu', 'pl', 'pt', 'pt-BR', 'tr', 'ja', 'zh-tw', 'ru'),'language.rtl' => array('ar','dv','fa','he','ps','ur'),'language.default' => 'en',
screen and adjust the default language.
• New languages need to be listed in:
• Important if your translation is 100% local.
templates/includes/header.php
38
Theming simpleSAMLphp
• Looks are everything…htt // i l l h /d /1 8/ i l l h th i– http://simplesamlphp.org/docs/1.8/simplesamlphp‐theming
Your own themecd /var/simplesamlmkdir –p modules/yourorg/themes/theme/default/includes/mkdir p modules/yourorg/www
• Serve CSS, PNG and favicon.ico from www by
touch modules/yourorg/default-enable
cp templates/includes/header.phptemplates/includes/header.phpmodules/yourorg/themes/theme/default/includes/
touch modules/yourorg/default-enable
changing the reference ‐ no SSL warning!OLD:<link rel="icon" type="image/icon" href="/<?php echo $this->data['baseurlpath']; ?>resources/icons/favicon.ico" />NEW:<link rel="icon" type="image/icon" href="<?php echoSimpleSAML_Module::getModuleUrl('yourorg/favicon.ico');?>" />
39
Shutdown your VM
Recommended