Dit artikel beschrijft de implementatie van PowerShell-interactie met de Google API om G Suite-gebruikers te manipuleren.
We maken gebruik van verschillende interne en clouddiensten binnen de organisatie. De autorisatie daarin komt voor het grootste deel neer op Google of Active Directory, waartussen we geen replica kunnen onderhouden; daarom moet u, wanneer een nieuwe medewerker vertrekt, een account in deze twee systemen aanmaken/activeren. Om het proces te automatiseren, hebben we besloten een script te schrijven dat informatie verzamelt en naar beide diensten verzendt.
Machtiging
Bij het opstellen van de eisen hebben we besloten om echte menselijke beheerders in te zetten voor de autorisatie; dit vereenvoudigt de analyse van acties in het geval van toevallige of opzettelijke grote veranderingen.
Ik heb gekozen voor het script dat wordt gebruikt voor autorisatie in desktopapplicaties. Ook is er de mogelijkheid om gebruik te maken van een serviceaccount, waarbij geen onnodige bewegingen van de gebruiker nodig zijn.
De onderstaande afbeelding is een schematische beschrijving van het geselecteerde scenario van de Google-pagina.
Eerst sturen we de gebruiker naar de authenticatiepagina van het Google-account, met vermelding van GET-parameters:
Applicatie ID
gebieden waartoe de applicatie toegang nodig heeft
het adres waarnaar de gebruiker wordt doorgestuurd na voltooiing van de procedure
de manier waarop we het token zullen bijwerken
Beveiligingscode
transmissieformaat voor verificatiecode
Nadat de autorisatie is voltooid, wordt de gebruiker doorgestuurd naar de pagina die is opgegeven in het eerste verzoek, met een fout- of autorisatiecode die wordt doorgegeven door GET-parameters
De applicatie (script) zal deze parameters moeten ontvangen en, indien de code ontvangen is, het volgende verzoek doen om tokens te verkrijgen
Als het verzoek correct is, retourneert de Google API:
Toegangstoken waarmee wij verzoeken kunnen doen
De geldigheidsduur van dit token
Vernieuwingstoken vereist om het toegangstoken te vernieuwen.
Eerst moet je naar de Google API-console gaan: Inloggegevens - Google API-console, selecteer de gewenste applicatie en maak in de sectie Credentials een OAuth-client-ID aan. Daar (of later, in de eigenschappen van de gemaakte ID) moet u de adressen opgeven waarnaar omleiding is toegestaan. In ons geval zijn dit verschillende localhost-vermeldingen met verschillende poorten (zie hieronder).
Om het gemakkelijker te maken om het scriptalgoritme te lezen, kunt u de eerste stappen weergeven in een aparte functie die toegangstokens en vernieuwingstokens voor de toepassing retourneert:
We stellen de client-ID en het clientgeheim in die zijn verkregen in de OAuth-client-ID-eigenschappen, en de codeverificatie is een reeks van 43 tot 128 tekens die willekeurig moet worden gegenereerd uit niet-gereserveerde tekens: [AZ] / [az] / [0-9 ] / "-" / "." / "_" / "~".
Deze code wordt dan opnieuw verzonden. Het elimineert de kwetsbaarheid waarbij een aanvaller een reactie kan onderscheppen die als omleiding wordt geretourneerd na autorisatie van de gebruiker.
U kunt een codeverificatie in het huidige verzoek in duidelijke tekst sturen (wat het betekenisloos maakt - dit is alleen geschikt voor systemen die SHA256 niet ondersteunen), of door een hash te maken met behulp van het SHA256-algoritme, dat moet worden gecodeerd in BASE64Url (verschillende uit Base64 door twee tabeltekens) en het verwijderen van de tekenregeluitgangen: =.
Vervolgens moeten we gaan luisteren naar http op de lokale machine om na autorisatie een antwoord te ontvangen, dat als een omleiding zal worden geretourneerd.
Administratieve taken worden uitgevoerd op een speciale server. We kunnen de mogelijkheid niet uitsluiten dat meerdere beheerders het script tegelijkertijd uitvoeren, dus het zal willekeurig een poort selecteren voor de huidige gebruiker, maar ik heb vooraf gedefinieerde poorten opgegeven omdat ze moeten ook als vertrouwd worden toegevoegd in de API-console.
toegangs_type=offline betekent dat de applicatie een verlopen token zelfstandig kan bijwerken zonder gebruikersinteractie met de browser, respons_type=code stelt het formaat in van hoe de code wordt geretourneerd (een verwijzing naar de oude autorisatiemethode, toen de gebruiker de code van de browser naar het script kopieerde), omvang geeft de omvang en het type toegang aan. Ze moeten worden gescheiden door spaties of %20 (volgens URL-codering). Een lijst met toegangsgebieden met typen vindt u hier: OAuth 2.0 Scopes voor Google API's.
Na ontvangst van de autorisatiecode stuurt de applicatie een sluitbericht naar de browser, stopt met luisteren op de poort en verzendt een POST-verzoek om het token te verkrijgen. We geven daarin de eerder opgegeven ID en het geheim van de console-API aan, het adres waarnaar de gebruiker wordt doorgestuurd en Grant_type in overeenstemming met de protocolspecificatie.
Als reactie hierop ontvangen we een Access token, de geldigheidsduur ervan in seconden, en een Refresh token, waarmee we het Access token kunnen bijwerken.
De applicatie moet tokens opslaan op een veilige plaats met een lange houdbaarheid, dus totdat we de ontvangen toegang intrekken, zal de applicatie het vernieuwingstoken niet retourneren. Aan het einde heb ik een verzoek toegevoegd om het token in te trekken; als de applicatie niet succesvol is voltooid en het vernieuwingstoken niet is geretourneerd, wordt de procedure opnieuw gestart (we vonden het onveilig om tokens lokaal op de terminal op te slaan, en dat doen we niet Ik wil de zaken niet ingewikkeld maken met cryptografie of de browser regelmatig openen).
Zoals je al hebt gemerkt, wordt bij het intrekken van een token Invoke-WebRequest gebruikt. In tegenstelling tot Invoke-RestMethod retourneert het de ontvangen gegevens niet in een bruikbaar formaat en wordt de status van het verzoek weergegeven.
Vervolgens vraagt het script u om de voor- en achternaam van de gebruiker in te voeren, waardoor een login + e-mailadres wordt gegenereerd.
verzoeken
De volgende verzoeken zijn: allereerst moet u controleren of er al een gebruiker met dezelfde login bestaat om een beslissing te krijgen over het maken van een nieuwe of het inschakelen van de huidige.
Ik besloot om alle verzoeken in het formaat van één functie met een selectie te implementeren, met behulp van switch:
Bij elk verzoek moet u een autorisatieheader verzenden met daarin het tokentype en het toegangstoken zelf. Momenteel is het tokentype altijd Bearer. Omdat we moeten controleren of het token niet is verlopen en het bijwerken na een uur vanaf het moment dat het is uitgegeven. Ik heb een verzoek opgegeven voor een andere functie die een toegangstoken retourneert. Hetzelfde stukje code staat aan het begin van het script bij ontvangst van het eerste toegangstoken:
Het email:$query-verzoek vraagt de API om te zoeken naar een gebruiker met precies dat e-mailadres, inclusief aliassen. U kunt ook een jokerteken gebruiken: =, :, :{PREFIX}*.
Om gegevens te verkrijgen, gebruikt u de GET-verzoekmethode om gegevens in te voegen (een account aanmaken of een lid aan een groep toevoegen) - POST, om bestaande gegevens bij te werken - PUT, om een record te verwijderen (bijvoorbeeld een lid uit een groep) - VERWIJDEREN.
Het script vraagt ook om een telefoonnummer (een niet-gevalideerde string) en om opname in een regionale distributiegroep. Het beslist welke organisatie-eenheid de gebruiker moet hebben op basis van de geselecteerde Active Directory-OE en komt met een wachtwoord:
do {
$phone = Read-Host "Телефон в формате +7хххххххх"
} while (-not $phone)
do {
$moscow = Read-Host "В Московский офис? (y/n) "
} while (-not (($moscow -eq 'y') -or ($moscow -eq 'n')))
$orgunit = '/'
if ($OU -like "*OU=Delivery,OU=Users,OU=ROOT,DC=rocket,DC=local") {
Write-host "Будет создана в /Team delivery"
$orgunit = "/Team delivery"
}
$Password = -join ( 48..57 + 65..90 + 97..122 | Get-Random -Count 12 | % {[char]$_})+"*Ba"
En dan begint hij het account te manipuleren:
$query = @{
email = $email
givenName = $firstname
familyName = $lastname
password = $password
phone = $phone
orgunit = $orgunit
}
if ($GMailExist) {
Write-Host "Запускаем изменение аккаунта" -f mag
(GoogleQuery 'UpdateAccount' $query) | fl
write-host "Не забудь проверить группы у включенного $Username в Google."
} else {
Write-Host "Запускаем создание аккаунта" -f mag
(GoogleQuery 'CreateAccount' $query) | fl
}
if ($moscow -eq "y"){
write-host "Добавляем в группу moscowoffice"
$query = @{
groupkey = '[email protected]'
email = $email
}
(GoogleQuery 'AddMember' $query) | fl
}
De functies voor het bijwerken en aanmaken van een account hebben een vergelijkbare syntaxis; niet alle extra velden zijn vereist; in het gedeelte met telefoonnummers moet u een array opgeven die maximaal één record kan bevatten met het nummer en het type ervan.
Om geen foutmelding te krijgen bij het toevoegen van een gebruiker aan een groep, kunnen we eerst controleren of hij al lid is van deze groep door van de gebruiker zelf een lijst met groepsleden of samenstelling op te vragen.
Het opvragen van het groepslidmaatschap van een specifieke gebruiker zal niet recursief zijn en zal alleen direct lidmaatschap tonen. Het opnemen van een gebruiker in een bovenliggende groep die al een onderliggende groep heeft waarvan de gebruiker lid is, zal lukken.
Conclusie
Het enige dat overblijft is om de gebruiker het wachtwoord voor het nieuwe account te sturen. We doen dit via sms en sturen algemene informatie met instructies en inloggen op een persoonlijke e-mail, die samen met een telefoonnummer is verstrekt door de recruitmentafdeling. Als alternatief kunt u geld besparen en uw wachtwoord naar een geheime telegramchat sturen, wat ook als de tweede factor kan worden beschouwd (MacBooks vormen een uitzondering).
Bedankt voor het lezen tot het einde. Ik zal blij zijn om suggesties te zien voor het verbeteren van de stijl van het schrijven van artikelen en ik wens dat je minder fouten ondervindt bij het schrijven van scripts =)
Lijst met links die thematisch nuttig kunnen zijn of eenvoudigweg vragen kunnen beantwoorden: