
    VhZ                         d dl mZmZmZ eZdZdZdZd dl	Z	d dl
Z
d dlmZmZ d dlmZmZ d dlmZ  G d	 d
e      Zd Zd Z	 	 	 	 ddZd Zd Zd Zd Zedk(  r e        yy)    )absolute_importdivisionprint_functiona3  
module: ipa_otptoken
author: justchris1 (@justchris1)
short_description: Manage FreeIPA OTPs
version_added: 2.5.0
description:
  - Add, modify, and delete One Time Passwords in IPA.
attributes:
  check_mode:
    support: full
  diff_mode:
    support: none
options:
  uniqueid:
    description: Unique ID of the token in IPA.
    required: true
    aliases: ["name"]
    type: str
  newuniqueid:
    description: If specified, the unique ID specified will be changed to this.
    type: str
  otptype:
    description:
      - Type of OTP.
      - B(Note:) Cannot be modified after OTP is created.
    type: str
    choices: [totp, hotp]
  secretkey:
    description:
      - Token secret (Base64).
      - If OTP is created and this is not specified, a random secret will be generated by IPA.
      - B(Note:) Cannot be modified after OTP is created.
    type: str
  description:
    description: Description of the token (informational only).
    type: str
  owner:
    description: Assigned user of the token.
    type: str
  enabled:
    description: Mark the token as enabled (default V(true)).
    default: true
    type: bool
  notbefore:
    description:
      - First date/time the token can be used.
      - In the format C(YYYYMMddHHmmss).
      - For example, V(20180121182022) will allow the token to be used starting on 21 January 2018 at 18:20:22.
    type: str
  notafter:
    description:
      - Last date/time the token can be used.
      - In the format C(YYYYMMddHHmmss).
      - For example, V(20200121182022) will allow the token to be used until 21 January 2020 at 18:20:22.
    type: str
  vendor:
    description: Token vendor name (informational only).
    type: str
  model:
    description: Token model (informational only).
    type: str
  serial:
    description: Token serial (informational only).
    type: str
  state:
    description: State to ensure.
    choices: ['present', 'absent']
    default: 'present'
    type: str
  algorithm:
    description:
      - Token hash algorithm.
      - B(Note:) Cannot be modified after OTP is created.
    choices: ['sha1', 'sha256', 'sha384', 'sha512']
    type: str
  digits:
    description:
      - Number of digits each token code will have.
      - B(Note:) Cannot be modified after OTP is created.
    choices: [6, 8]
    type: int
  offset:
    description:
      - TOTP token / IPA server time difference.
      - B(Note:) Cannot be modified after OTP is created.
    type: int
  interval:
    description:
      - Length of TOTP token code validity in seconds.
      - B(Note:) Cannot be modified after OTP is created.
    type: int
  counter:
    description:
      - Initial counter for the HOTP token.
      - B(Note:) Cannot be modified after OTP is created.
    type: int
extends_documentation_fragment:
  - community.general.ipa.documentation
  - community.general.attributes
a  
- name: Create a totp for pinky, allowing the IPA server to generate using defaults
  community.general.ipa_otptoken:
    uniqueid: Token123
    otptype: totp
    owner: pinky
    ipa_host: ipa.example.com
    ipa_user: admin
    ipa_pass: topsecret

- name: Create a 8 digit hotp for pinky with sha256 with specified validity times
  community.general.ipa_otptoken:
    uniqueid: Token123
    enabled: true
    otptype: hotp
    digits: 8
    secretkey: UMKSIER00zT2T2tWMUlTRmNlekRCbFQvWFBVZUh2dElHWGR6T3VUR3IzK2xjaFk9
    algorithm: sha256
    notbefore: 20180121182123
    notafter: 20220121182123
    owner: pinky
    ipa_host: ipa.example.com
    ipa_user: admin
    ipa_pass: topsecret

- name: Update Token123 to indicate a vendor, model, serial number (info only), and description
  community.general.ipa_otptoken:
    uniqueid: Token123
    vendor: Acme
    model: acme101
    serial: SerialNumber1
    description: Acme OTP device
    ipa_host: ipa.example.com
    ipa_user: admin
    ipa_pass: topsecret

- name: Disable Token123
  community.general.ipa_otptoken:
    uniqueid: Token123
    enabled: false
    ipa_host: ipa.example.com
    ipa_user: admin
    ipa_pass: topsecret

- name: Rename Token123 to TokenABC and enable it
  community.general.ipa_otptoken:
    uniqueid: Token123
    newuniqueid: TokenABC
    enabled: true
    ipa_host: ipa.example.com
    ipa_user: admin
    ipa_pass: topsecret
z\
otptoken:
  description: OTP Token as returned by IPA API.
  returned: always
  type: dict
N)AnsibleModulesanitize_keys)	IPAClientipa_argument_spec)	to_nativec                   6     e Zd Z fdZd Zd Zd Zd Z xZS )OTPTokenIPAClientc                 2    t         t        |   ||||       y )N)superr   __init__)selfmodulehostportprotocol	__class__s        r/home/dcms/DCMS/lib/python3.12/site-packages/ansible_collections/community/general/plugins/modules/ipa_otptoken.pyr   zOTPTokenIPAClient.__init__   s    /dHM    c           	      4    | j                  dd d|ddd      S )Notptoken_findT0)allipatokenuniqueid	timelimit	sizelimitmethodnameitem
_post_jsonr   r!   s     r   r   zOTPTokenIPAClient.otptoken_find   s-    oDt\`UXUXHZ [ 	[r   c                 *    | j                  d||      S )Notptoken_addr   r#   r   r!   r"   s      r   r'   zOTPTokenIPAClient.otptoken_add       n4dKKr   c                 *    | j                  d||      S )Notptoken_modr   r#   r(   s      r   r+   zOTPTokenIPAClient.otptoken_mod   r)   r   c                 (    | j                  d|      S )Notptoken_del)r    r!   r#   r%   s     r   r-   zOTPTokenIPAClient.otptoken_del   s    n4@@r   )	__name__
__module____qualname__r   r   r'   r+   r-   __classcell__)r   s   @r   r   r      s!    N[LLAr   r   c                 t    t        j                  t        j                  |             j                  d      }|S )z'Converts base64 string to base32 stringascii)base64	b32encode	b64decodedecode)base64_string
b32_strings     r   base64_to_base32r:      .    !!&"2"2="ABII'RJr   c                 t    t        j                  t        j                  |             j                  d      }|S )z'Converts base32 string to base64 stringr3   )r4   	b64encode	b32decoder7   )base32_string
b64_strings     r   base32_to_base64rA      r;   r   c                    i }|||| d   <   |||| d   <   ||j                         || d   <   |t        |      || d   <   |||| d   <   |||| d   <   ||rdnd|| d	   <   ||d
z   || d   <   |	|	d
z   || d   <   |
|
|| d   <   |||| d   <   |||| d   <   |||| d   <   |t        |      || d   <   |t        |      || d   <   |t        |      || d   <   |t        |      || d   <   |S )z+Create the dictionary of settings passed inuniqueidnewuniqueidotptype	secretkeydescriptionownerFTenabledZ	notbeforenotaftervendormodelserial	algorithmdigitsoffsetintervalcounter)upperr:   str)ansible_to_iparC   rD   rE   rF   rG   rH   rI   rK   rL   rM   rN   rO   rP   rQ   rR   rS   rT   otptokens                      r   get_otptoken_dictrY      s    H/7
+,2=./.5mmo	*+ 1A0K,-2=./,1()7>eD	*+09C,-/7#~
+,-3)*,1()-3)*09,--0[)*-0[)*/28}
+,.1'l	*+Or   c                    | }t               }|D ]#  }|| v s| |   |||   <   |j                  |       % |D ]k  }||v st        ||   t              st	        ||         dk(  s.|dv rt        ||   d         ||<   G|dk(  rt        ||   d         ||<   a||   d   ||<   m d|v rt        |d   t              rd|d   v rJ|j                  |d   d          |d   d   }|j                  d       ||d<   |j                  |       ||fS d|d   v rb|j                  |d   d          |d   d   }t        |      }|j                  d       ||d<   |j                  |       |j                  |       ||fS )a	  Transform the output received by IPA to a format more friendly
       before it is returned to the user.  IPA returns even simple
       strings as a list of strings.  It also returns bools and
       int as string.  This function cleans that up before return.
       )rQ   rR   rS   rT   r   rI   rF   
__base64__
__base32__)
setpop
isinstancelistlenintbooldictaddrA   )	ipa_otptokenrW   ipa_to_ansibleupdated_otptokensanitize_stringsipa_parameteransible_parameterb64keyb32keys	            r   transform_outputro     s     $
 u ( 0L(>J=>Y^M:;  /0 , a 00*+<=tDM]^oMpIquvIv$(SS:=>NO`>abc>d:e$%67&)3:>?OPa?bcd?e:f$%67:JK\:]^_:`$%67a &&&{3T:/<< $$%5k%B<%PQ)+6|D $$[106 - $$V, --- !1+!>> $$%5k%B<%PQ)+6|D)&1 $$[106 - $$V, $$V,---r   c                    d}|D ]  }| |   |v s| |   |v s|| |      }|dk(  r	|| |      }nt        || |            dk7  r|j                  d       |dk(  rat        |      }|| |      d   d   }d|| |      d   v r|| |      d   d   }n7d	|| |      d   v r|| |      d   d	   }	t        |	      }
|
}nd
}n|| |      d   }||k7  sd}d|z   dz   dz   t        |      z   dz   t        |      z   dz   }|j                  |        |S )a  Checks to see if the requested modifications are valid.  Some elements
       cannot be modified after initial creation.  However, we still want to
       validate arguments that are specified, but are not different than what
       is currently set on the server.
    TrE   r[   zjInvariant fail: Return value from IPA is not a list of length 1.  Please open a bug report for the module.msgrF   r   r\   r]   NFzParameter 'z' cannot be changed once z;the OTP is created and the requested value specified here (z.) differs from what is set in the IPA server ())rb   	fail_jsonrA   rV   )rW   r   rg   module_otptokenunmodifiable_after_creationmodifications_valid	parameter	mod_value	ipa_valuern   rm   fail_messages               r   validate_modificationsr|   ;  s    0 *3	)$7N9<UYe<e'y(ABI I%(	)BC	|N9$=>?1D$$ +c$ e+
 !1 ;I !-^I-F G J< XI#|N94M'Nq'QQ$0	1J$KA$N|$\	%nY6O)PQR)SS!-nY.G!H!KL!Y!1&!9$*	$(	 ,^I-F G JII%&+# -	 9<W W ]!^ #I!/ !Q!Q #&i.	!1 47	!7
   \ 2U*3X r   c                    i ddddddddd	d	d
dddddddddddddddddddddd d!}|j                         D ci c]  \  }}||
 }}}g d"}| j                  d#   }| j                  d   }t        d2i d$|d| j                  j                  d      d| j                  j                  d      d| j                  j                  d      d| j                  j                  d      d	| j                  j                  d	      d
| j                  j                  d
      d| j                  j                  d      d| j                  j                  d      d| j                  j                  d      d| j                  j                  d      d| j                  j                  d      d| j                  j                  d      d| j                  j                  d      d| j                  j                  d      d| j                  j                  d      d| j                  j                  d      d | j                  j                  d       }	|j	                  |%      }
|d   |	v r8|j	                  |	|d      %      }|r| j                  d&|	|d      z   d'z   (       d)}|d*k(  r|
std+}| j                  s.|d   |	v r*|	|d      |	|d   <   |	|d      }|	j                  |d          |d   |	v r|	j                  |d          d+|	d,<   |j                  ||	-      }
nt        || |
|	|      s| j                  d.(       |D ]  }||   |	v s|	j                  ||            |j                  |
|	/      }t        |      d0kD  rdd+}| j                  sV|d   |	v r|	j                  |d          d+|	d,<   |j                  ||	-      }
n"|
r d+}| j                  s|j                  |%       t        |
||      \  }
}| j                  j!                  |      | _        t#        |
| j                  1      }||fS c c}}w )3NrC   r   rD   renamerE   typerF   ipatokenotpkeyrG   rH   ipatokenownerrI   ipatokendisabledrK   ipatokennotbeforerL   ipatokennotafterrM   ipatokenvendorrN   ipatokenmodelrO   ipatokenserialrP   ipatokenotpalgorithmrQ   ipatokenotpdigitsrR   ipatokentotpclockoffsetrS   ipatokentotptimesteprT   ipatokenhotpcounter)rE   rF   rP   rQ   rR   rS   rT   staterW   )r!   z(Requested rename through newuniqueid to z3 failed because the new unique id is already in userq   FpresentTr   )r!   r"   z/Modifications requested in module are not valid)ipa_datamodule_datar   )objno_log_strings )itemsparamsrY   getr   rt   
check_moder_   r'   r|   get_diffrb   r+   r-   ro   no_log_valuesunionr   )r   clientrW   kvrh   rv   r   rC   ru   rg   ipa_otptoken_newchangedxdiffrj   sanitized_otptokens                    r   ensurer   t  sN   8j"4 8#X88 "#38 $]	8
 8  !38 "#68 !"48  08 8  08 "#98  38  98 !"88   !6!8N& (6';';'=>tq!ad>N>#NMM'"E}}Z(H' N~ N171B1B:1NN4:MM4E4Em4TN 170A0A)0LN 39--2C2CK2P	N
 5;MM4E4Em4TN /5mm.?.?.HN 170A0A)0LN 39--2C2CK2PN 281B1B:1NN 06}}/@/@/JN /5mm.?.?.HN 06}}/@/@/JN 39--2C2CK2PN 06}}/@/@/JN 06}}/@/@/JN  281B1B:1N!N" 170A0A)0L#NO& ''X'6Lm$7!//_^TaEb5c/d"L"1.2O"P#Q"W#X Z G	G$$ "-0OCBQR`anRoBpON:$>?.~m/LMH#''}(EF
 "*-@#''z(BC)-&%222W).&,*9;VX  %V W 1 ;!!$7#''q(9:; ??Lo?VD4y1}((
 &j1_D'++N:,FG-1OE*#)#6#6H?#6#[LG$$###2 &6lNTb%c"L"!//556FGF&<H\H\]&&&} ?s   	Qc                     t               } | j                  t        ddgd      t        d      t        dddg      t        dd	      t        d      t        d      t        d
d      t        d      t        d      t        d      t        d      t        d      t        dddgd      t        dg d      t        dddg      t        d      t        d      t        d             t        | d      }t	        ||j
                  d   |j
                  d   |j
                  d         }	 |j                  |j
                  d   |j
                  d          t        ||      \  }}|j                         y # t        $ r8}|j                  t        |      t        j                                Y d }~Pd }~ww xY w)NrV   r!   T)r   aliasesrequired)r   totphotp)r   choices)r   no_logrd   )r   defaultr   absent)r   r   r   )sha1sha256sha384sha512rc         )rC   rD   rE   rF   rG   rH   rI   rK   rL   rM   rN   rO   r   rP   rQ   rR   rS   rT   )argument_specsupports_check_modeipa_hostipa_portipa_prot)r   r   r   r   ipa_useripa_pass)usernamepassword)rr   	exception)r   rX   )r	   updatere   r   r   r   loginr   	Exceptionrt   r
   	traceback
format_exc	exit_json)r   r   r   r   rX   es         r   mainr     s   %'M$EF8d"S%)u%5!%566:J!K#'U4#@%)u%5#/!%64!@#'U#3"&E"2 $% 0#/ $% 0#H8MW`a#'U<b#c $%!Q @ $% 0"&E"2!%5!1#  3& /35F f$*MM*$=$*MM*$=(.j(ACF
MfmmJ7$mmJ7 	 	9"662 Wx8  MYq\Y5I5I5KLLMs   8<F 	G	.GG	__main__)NNNNNNNNNNNNNNNNN)
__future__r   r   r   r   __metaclass__DOCUMENTATIONEXAMPLESRETURNr4   r   ansible.module_utils.basicr   r   >ansible_collections.community.general.plugins.module_utils.ipar   r	   +ansible.module_utils.common.text.convertersr
   r   r:   rA   rY   ro   r|   r   r   r.   r   r   r   <module>r      s    A @cJ4l
   C g AA	 A( ~BJNSW-11h0.f6rt'n$9N zF r   