Kuunda Watumiaji wa Google kutoka PowerShell kupitia API

Hi!

Makala haya yataelezea utekelezaji wa mwingiliano wa PowerShell na API ya Google ili kudanganya watumiaji wa G Suite.

Tunatumia huduma kadhaa za ndani na za wingu kote katika shirika. Kwa sehemu kubwa, uidhinishaji ndani yake unakuja kwa Google au Saraka Inayotumika, ambapo hatuwezi kudumisha nakala; kwa hivyo, mfanyakazi mpya anapoondoka, unahitaji kufungua/kuwezesha akaunti katika mifumo hii miwili. Ili kufanya mchakato kiotomatiki, tuliamua kuandika hati inayokusanya habari na kuituma kwa huduma zote mbili.

Authorization

Wakati wa kuandaa mahitaji, tuliamua kutumia wasimamizi halisi wa kibinadamu kwa idhini; hii hurahisisha uchanganuzi wa vitendo katika tukio la mabadiliko makubwa ya bahati mbaya au ya kukusudia.

API za Google hutumia itifaki ya OAuth 2.0 kwa uthibitishaji na uidhinishaji. Kesi za matumizi na maelezo ya kina zaidi yanaweza kupatikana hapa: Kwa kutumia OAuth 2.0 kufikia API za Google.

Nilichagua hati ambayo inatumika kwa idhini katika programu za mezani. Pia kuna chaguo la kutumia akaunti ya huduma, ambayo hauhitaji harakati zisizohitajika kutoka kwa mtumiaji.

Picha iliyo hapa chini ni maelezo ya kimkakati ya hali iliyochaguliwa kutoka kwa ukurasa wa Google.

Kuunda Watumiaji wa Google kutoka PowerShell kupitia API

  1. Kwanza, tunatuma mtumiaji kwenye ukurasa wa uthibitishaji wa Akaunti ya Google, tukibainisha vigezo vya GET:
    • kitambulisho cha maombi
    • maeneo ambayo programu inahitaji ufikiaji
    • anwani ambayo mtumiaji ataelekezwa upya baada ya kukamilisha utaratibu
    • jinsi tutakavyosasisha ishara
    • Kanuni ya Usalama
    • umbizo la utumaji msimbo wa uthibitishaji

  2. Baada ya idhini kukamilika, mtumiaji ataelekezwa kwenye ukurasa ulioainishwa katika ombi la kwanza, na hitilafu au msimbo wa uidhinishaji ukipitishwa na vigezo vya GET.
  3. Programu (hati) itahitaji kupokea vigezo hivi na, ikiwa imepokea msimbo, fanya ombi lifuatalo ili kupata ishara.
  4. Ikiwa ombi ni sahihi, API ya Google inarudi:
    • Tokeni ya ufikiaji ambayo tunaweza kufanya maombi nayo
    • Kipindi cha uhalali wa tokeni hii
    • Inahitajika kuonyesha upya tokeni ili kuonyesha upya tokeni ya Ufikiaji.

Kwanza unahitaji kwenda kwa koni ya API ya Google: Kitambulisho - Dashibodi ya API ya Google, chagua programu unayotaka na katika sehemu ya Vitambulisho unda kitambulisho cha OAuth cha mteja. Huko (au baadaye, katika mali ya kitambulisho kilichoundwa) unahitaji kutaja anwani ambazo uelekezaji upya unaruhusiwa. Kwa upande wetu, haya yatakuwa maingizo kadhaa ya mwenyeji na bandari tofauti (tazama hapa chini).

Ili kuifanya iwe rahisi zaidi kusoma algoriti ya hati, unaweza kuonyesha hatua za kwanza katika utendaji tofauti ambao utarudisha Ufikiaji na kuonyesha upya ishara za programu:

$client_secret = 'Our Client Secret'
$client_id = 'Our Client ID'
function Get-GoogleAuthToken {
  if (-not [System.Net.HttpListener]::IsSupported) {
    "HttpListener is not supported."
    exit 1
  }
  $codeverifier = -join ((65..90) + (97..122) + (48..57) + 45 + 46 + 95 + 126 |Get-Random -Count 60| % {[char]$_})
  $hasher = new-object System.Security.Cryptography.SHA256Managed
  $hashByteArray = $hasher.ComputeHash([System.Text.Encoding]::UTF8.GetBytes($codeverifier))
  $base64 = ((([System.Convert]::ToBase64String($hashByteArray)).replace('=','')).replace('+','-')).replace('/','_')
  $ports = @(10600,15084,39700,42847,65387,32079)
  $port = $ports[(get-random -Minimum 0 -maximum 5)]
  Write-Host "Start browser..."
  Start-Process "https://accounts.google.com/o/oauth2/v2/auth?code_challenge_method=S256&code_challenge=$base64&access_type=offline&client_id=$client_id&redirect_uri=http://localhost:$port&response_type=code&scope=https://www.googleapis.com/auth/admin.directory.user https://www.googleapis.com/auth/admin.directory.group"
  $listener = New-Object System.Net.HttpListener
  $listener.Prefixes.Add("http://localhost:"+$port+'/')
  try {$listener.Start()} catch {
    "Unable to start listener."
    exit 1
  }
  while (($code -eq $null)) {
    $context = $listener.GetContext()
    Write-Host "Connection accepted" -f 'mag'
    $url = $context.Request.RawUrl
    $code = $url.split('?')[1].split('=')[1].split('&')[0]
    if ($url.split('?')[1].split('=')[0] -eq 'error') {
      Write-Host "Error!"$code -f 'red'
      $buffer = [System.Text.Encoding]::UTF8.GetBytes("Error!"+$code)
      $context.Response.ContentLength64 = $buffer.Length
      $context.Response.OutputStream.Write($buffer, 0, $buffer.Length)
      $context.Response.OutputStream.Close()
      $listener.Stop()
      exit 1
    }
    $buffer = [System.Text.Encoding]::UTF8.GetBytes("Now you can close this browser tab.")
    $context.Response.ContentLength64 = $buffer.Length
    $context.Response.OutputStream.Write($buffer, 0, $buffer.Length)
    $context.Response.OutputStream.Close()
    $listener.Stop()
  }
  Return Invoke-RestMethod -Method Post -Uri "https://www.googleapis.com/oauth2/v4/token" -Body @{
    code = $code
    client_id = $client_id
    client_secret = $client_secret
    redirect_uri = 'http://localhost:'+$port
    grant_type = 'authorization_code'
    code_verifier   = $codeverifier
  }
  $code = $null

Tunaweka Kitambulisho cha Mteja na Siri ya Mteja zilizopatikana katika sifa za kitambulisho cha mteja cha OAuth, na kithibitishaji cha msimbo ni mfuatano wa herufi 43 hadi 128 ambazo lazima zitolewe bila mpangilio kutoka kwa herufi ambazo hazijahifadhiwa: [AZ] / [az] / [0-9 ] / "-" / "." / "_" / "~".

Nambari hii itatumwa tena. Huondoa uwezekano wa kuathiriwa ambapo mshambulizi anaweza kuingilia jibu lililorejeshwa kama kuelekezwa kwingine baada ya idhini ya mtumiaji.
Unaweza kutuma kithibitishaji cha msimbo katika ombi la sasa kwa maandishi wazi (ambayo huifanya lisiwe na maana - hii inafaa tu kwa mifumo ambayo haitumii SHA256), au kwa kuunda heshi kwa kutumia algoriti ya SHA256, ambayo lazima iambatishwe katika BASE64Url (inayotofautiana). kutoka kwa Base64 kwa herufi mbili za jedwali) na kuondoa miisho ya mstari wa herufi: =.

Ifuatayo, tunahitaji kuanza kusikiliza http kwenye mashine ya ndani ili kupokea jibu baada ya idhini, ambayo itarejeshwa kama kuelekezwa kwingine.

Kazi za kiutawala zinafanywa kwenye seva maalum, hatuwezi kuondoa uwezekano kwamba wasimamizi kadhaa wataendesha hati kwa wakati mmoja, kwa hivyo itachagua kwa nasibu bandari kwa mtumiaji wa sasa, lakini nilitaja bandari zilizoainishwa kwa sababu. lazima pia waongezwe kama inavyoaminika katika kiweko cha API.

access_type=nje ya mtandao inamaanisha kuwa programu inaweza kusasisha tokeni iliyoisha muda wake yenyewe bila mwingiliano wa mtumiaji na kivinjari,
majibu_aina=msimbo huweka umbizo la jinsi msimbo utakavyorejeshwa (rejeleo la mbinu ya zamani ya idhini, wakati mtumiaji alinakili msimbo kutoka kwa kivinjari hadi kwenye hati),
wigo inaonyesha upeo na aina ya ufikiaji. Lazima zitenganishwe na nafasi au %20 (kulingana na Usimbaji wa URL). Orodha ya maeneo ya ufikiaji yenye aina inaweza kuonekana hapa: Mawanda ya OAuth 2.0 ya API za Google.

Baada ya kupokea msimbo wa idhini, programu itarudi ujumbe wa karibu kwa kivinjari, kuacha kusikiliza kwenye bandari na kutuma ombi la POST ili kupata ishara. Tunaonyesha ndani yake kitambulisho na siri iliyoainishwa hapo awali kutoka kwa API ya kiweko, anwani ambayo mtumiaji ataelekezwa kwingine na grant_type kwa mujibu wa vipimo vya itifaki.

Kwa kujibu, tutapokea tokeni ya Ufikiaji, muda wa uhalali wake kwa sekunde, na tokeni ya Onyesha upya, ambayo kwayo tunaweza kusasisha tokeni ya Ufikiaji.

Programu lazima ihifadhi tokeni mahali salama na muda mrefu wa kuhifadhi, kwa hivyo hadi tutakapobatilisha ufikiaji uliopokelewa, programu haitarudisha ishara ya kuonyesha upya. Mwishowe, niliongeza ombi la kubatilisha ishara; ikiwa maombi hayakukamilishwa kwa mafanikio na ishara ya kusasisha haikurejeshwa, itaanza utaratibu tena (tuliona kuwa sio salama kuhifadhi tokeni ndani ya kituo, na hatufanyi. sitaki kutatanisha mambo na kriptografia au kufungua kivinjari mara kwa mara).

do {
  $token_result = Get-GoogleAuthToken
  $token = $token_result.access_token
  if ($token_result.refresh_token -eq $null) {
    Write-Host ("Session is not destroyed. Revoking token...")
    Invoke-WebRequest -Uri ("https://accounts.google.com/o/oauth2/revoke?token="+$token)
  }
} while ($token_result.refresh_token -eq $null)
$refresh_token = $token_result.refresh_token
$minute = ([int]("{0:mm}" -f ([timespan]::fromseconds($token_result.expires_in))))+((Get-date).Minute)-2
if ($minute -lt 0) {$minute += 60}
elseif ($minute -gt 59) {$minute -=60}
$token_expire = @{
  hour = ([int]("{0:hh}" -f ([timespan]::fromseconds($token_result.expires_in))))+((Get-date).Hour)
  minute = $minute
}

Kama ulivyoona tayari, wakati wa kubatilisha ishara, Invoke-WebRequest inatumika. Tofauti na Invoke-RestMethod, hairejeshi data iliyopokelewa katika umbizo inayoweza kutumika na inaonyesha hali ya ombi.

Ifuatayo, hati inakuuliza uweke jina la kwanza na la mwisho la mtumiaji, ikitoa kuingia + barua pepe.

Maombi

Maombi yanayofuata yatakuwa - kwanza kabisa, unahitaji kuangalia ikiwa mtumiaji aliye na kuingia sawa tayari yupo ili kupata uamuzi wa kuunda mpya au kuwezesha ya sasa.

Niliamua kutekeleza maombi yote katika muundo wa kazi moja na uteuzi, kwa kutumia swichi:

function GoogleQuery {
  param (
    $type,
    $query
  )
  switch ($type) {
    "SearchAccount" {
      Return Invoke-RestMethod -Method Get -Uri "https://www.googleapis.com/admin/directory/v1/users" -Headers @{Authorization = "Bearer "+(Get-GoogleToken)} -Body @{
        domain = 'rocketguys.com'
        query  = "email:$query"
      }
    }
    "UpdateAccount" {
      $body = @{
        name  = @{
          givenName = $query['givenName']
          familyName = $query['familyName']
        }
        suspended = 'false'
        password = $query['password']
        changePasswordAtNextLogin = 'true'
        phones = @(@{
          primary = 'true'
          value = $query['phone']
          type = "mobile"
        })
        orgUnitPath = $query['orgunit']
      }
      Return Invoke-RestMethod -Method Put -Uri ("https://www.googleapis.com/admin/directory/v1/users/"+$query['email']) -Headers @{Authorization = "Bearer "+(Get-GoogleToken)} -Body (ConvertTo-Json $body) -ContentType 'application/json; charset=utf-8'
    }
    
    "CreateAccount" {
      $body = @{
        primaryEmail = $query['email']
        name  = @{
          givenName = $query['givenName']
          familyName = $query['familyName']
        }
        suspended = 'false'
        password = $query['password']
        changePasswordAtNextLogin = 'true'
        phones = @(@{
          primary = 'true'
          value = $query['phone']
          type = "mobile"
        })
        orgUnitPath = $query['orgunit']
      }
      Return Invoke-RestMethod -Method Post -Uri "https://www.googleapis.com/admin/directory/v1/users" -Headers @{Authorization = "Bearer "+(Get-GoogleToken)} -Body (ConvertTo-Json $body) -ContentType 'application/json; charset=utf-8'
    }
    "AddMember" {
      $body = @{
        userKey = $query['email']
      }
      $ifrequest = Invoke-RestMethod -Method Get -Uri "https://www.googleapis.com/admin/directory/v1/groups" -Headers @{Authorization = "Bearer "+(Get-GoogleToken)} -Body $body
      $array = @()
      foreach ($group in $ifrequest.groups) {$array += $group.email}
      if ($array -notcontains $query['groupkey']) {
        $body = @{
          email = $query['email']
          role = "MEMBER"
        }
        Return Invoke-RestMethod -Method Post -Uri ("https://www.googleapis.com/admin/directory/v1/groups/"+$query['groupkey']+"/members") -Headers @{Authorization = "Bearer "+(Get-GoogleToken)} -Body (ConvertTo-Json $body) -ContentType 'application/json; charset=utf-8'
      } else {
        Return ($query['email']+" now is a member of "+$query['groupkey'])
      }
    }
  }
}

Katika kila ombi, unahitaji kutuma kichwa cha Uidhinishaji kilicho na aina ya ishara na tokeni ya Ufikiaji yenyewe. Hivi sasa, aina ya ishara daima ni Mbebaji. Kwa sababu tunahitaji kuangalia kuwa tokeni haijaisha muda wake na kuisasisha baada ya saa moja tangu ilipotolewa, nilitaja ombi la chaguo la kukokotoa ambalo hurejesha tokeni ya Ufikiaji. Sehemu hiyo hiyo ya nambari iko mwanzoni mwa hati wakati wa kupokea ishara ya Ufikiaji wa kwanza:

function Get-GoogleToken {
  if (((Get-date).Hour -gt $token_expire.hour) -or (((Get-date).Hour -ge $token_expire.hour) -and ((Get-date).Minute -gt $token_expire.minute))) {
  Write-Host "Token Expired. Refreshing..."
    $request = (Invoke-RestMethod -Method Post -Uri "https://www.googleapis.com/oauth2/v4/token" -ContentType 'application/x-www-form-urlencoded' -Body @{
      client_id = $client_id
      client_secret = $client_secret
      refresh_token = $refresh_token
      grant_type = 'refresh_token'
    })
    $token = $request.access_token
    $minute = ([int]("{0:mm}" -f ([timespan]::fromseconds($request.expires_in))))+((Get-date).Minute)-2
    if ($minute -lt 0) {$minute += 60}
    elseif ($minute -gt 59) {$minute -=60}
    $script:token_expire = @{
      hour = ([int]("{0:hh}" -f ([timespan]::fromseconds($request.expires_in))))+((Get-date).Hour)
      minute = $minute
    }
  }
  return $token
}

Kuangalia kuingia kwa uwepo:

function Check_Google {
  $query = (GoogleQuery 'SearchAccount' $username)
  if ($query.users -ne $null) {
    $user = $query.users[0]
    Write-Host $user.name.fullName' - '$user.PrimaryEmail' - suspended: '$user.Suspended
    $GAresult = $user
  }
  if ($GAresult) {
      $return = $GAresult
  } else {$return = 'gg'}
  return $return
}

Barua pepe:$query request itaomba API kutafuta mtumiaji aliye na barua pepe hiyo haswa, ikijumuisha lakabu. Unaweza pia kutumia wildcard: =, :, :{PREFIX}*.

Ili kupata data, tumia njia ya ombi la GET, kuingiza data (kuunda akaunti au kuongeza mwanachama kwenye kikundi) - POST, kusasisha data iliyopo - PUT, kufuta rekodi (kwa mfano, mwanachama kutoka kwa kikundi) - FUTA.

Hati pia itauliza nambari ya simu (kamba isiyothibitishwa) na kujumuishwa katika kikundi cha usambazaji wa kikanda. Huamua ni kitengo kipi cha shirika ambacho mtumiaji anapaswa kuwa nacho kulingana na OU ya Saraka Inayotumika iliyochaguliwa na kuja na nenosiri:

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"

Na kisha anaanza kudanganya akaunti:

$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
}

Kazi za kusasisha na kuunda akaunti zina syntax sawa; sio sehemu zote za ziada zinahitajika; katika sehemu iliyo na nambari za simu, unahitaji kutaja safu ambayo inaweza kuwa na rekodi moja na nambari na aina yake.

Ili tusipokee hitilafu wakati wa kuongeza mtumiaji kwenye kikundi, tunaweza kwanza kuangalia ikiwa tayari ni mshiriki wa kikundi hiki kwa kupata orodha ya washiriki wa kikundi au utunzi kutoka kwa mtumiaji mwenyewe.

Kuuliza uanachama wa kikundi wa mtumiaji mahususi hakutajirudia na kutaonyesha tu uanachama wa moja kwa moja. Ikiwa ni pamoja na mtumiaji katika kikundi cha wazazi ambacho tayari kina kikundi cha watoto ambacho mtumiaji ni mwanachama kitafaulu.

Hitimisho

Kinachobaki ni kutuma mtumiaji nenosiri la akaunti mpya. Tunafanya hivyo kupitia SMS, na kutuma maelezo ya jumla kwa maelekezo na kuingia kwa barua pepe ya kibinafsi, ambayo, pamoja na nambari ya simu, ilitolewa na idara ya kuajiri. Kama mbadala, unaweza kuokoa pesa na kutuma nenosiri lako kwa gumzo la siri la telegraph, ambalo linaweza pia kuzingatiwa kuwa jambo la pili (MacBooks itakuwa ubaguzi).

Asante kwa kusoma hadi mwisho. Nitafurahi kuona maoni ya kuboresha mtindo wa uandishi wa nakala na ninatamani upate makosa machache wakati wa kuandika maandishi =)

Orodha ya viungo ambavyo vinaweza kuwa muhimu kimaudhui au kujibu maswali kwa urahisi:

Chanzo: mapenzi.com

Kuongeza maoni