Escrito por

Software Architect at Visum
Artigo Yuri Marx · Nov. 30, 2021 3m read

O poder do XDATA aplicado à segurança da API

O XData (https://docs.intersystems.com/irislatest/csp/docbook/DocBook.UI.Page.cls?KEY=GOBJ_XDATA) é um recurso poderoso para definir informações de documentação e metadados para classes e métodos. A classe% CSP.REST usa XDATA para mapear chamadas REST(https://docs.intersystems.com/irislatest/csp/docbook/DocBook.UI.Page.cls?KEY=GREST_csprest), portanto, neste artigo, você verá como usar XData em seus aplicativos como código, não apenas como documentação.

Quando você escreve comentários / definições XData, o IRIS os armazena em %Dictionary.ClassDefinition (para classes) e %Dictionary.MethodDefinition (para métodos). Se você consultar essas tabelas, poderá obter informações de metadados e escrever código para essa configuração de metadados. %CSP.REST faz isso quando você escreve seus mapeamentos REST para seus serviços REST usando ObjectScript.

Eu escrevi um aplicativo que está usando XDATA para impor regras de autorização aos endpoints do método de classe, consulte:

///Retreive all the records of dc.Sample.Person
///@security.and: roles: { PersonAdmin }  
ClassMethodGetAllPersons()As%Status
{
 
    #dimtSCAs%Status=$$$OK
....
}

O @ security.and não existe no IRIS. Portanto, preciso ler essa configuração e escrever o código para garantir o acesso aos usuários apenas com a role PersonAdmin.

Para obter este @ security.and, você precisa ler este XData. Veja:

ClassMethodGetXDataContent(className,methodName)As%String
{
     
    SetqryXdata="SELECT parent, Name, Description FROM %Dictionary.MethodDefinition WHERE parent = ? and Name = ?"
    SetstmXdata=##class(%SQL.Statement).%New()
    SetqStatus=stmXdata.%Prepare(qryXdata)
    IfqStatus'=1{Write"%Prepare  failed:"Do$System.Status.DisplayError(qStatus)Quit}
    SetrsetXdata=stmXdata.%Execute(className,methodName)

 

    WhilersetXdata.%Next(){
        // Return rsetXdata.Name
        ReturnrsetXdata.Description
    }
}

Com esse método, você pode obter qualquer conteúdo xdata para métodos.

Agora, para restringir o acesso apenas aos usuários com a role PersonAdmin é simples, você precisa fazer o override do método de classe AccessCheck da classe% CSP.REST. Veja:

ClassMethodAccessCheck(OutputpAuthorizedAs%Boolean=0)As%Status
{
 
  Do##super()
 
  Setmessage={}
 
  SettSC=$$$OK
 
  Setmessage.verb=%request.Method

 

  Setmessage.url=%request.URL

 

  Setmessage.url="/"_$REPLACE(message.url,%request.Application,"")

 

  Setmessage.application=%request.Application
 
  SetmethodName=""
  Do..GetClassMethodName(message.url,%request.Method,.methodName)
 
  Setmessage.method=methodName

 

  Setxdata=##class(dc.SecurityMediator.XDataUtil).GetXDataContent($CLASSNAME(),methodName)

 

  Do..GetSecurityRules(xdata,.rules,.roles,.header,.operator)

 

  SetUserRoles=$LISTFROMSTRING($ROLES,",")
  SetRolesAllowed=UserRoles
 
  If$FIND(xdata,"@security")>0{
    SetRolesAllowed=$LISTFROMSTRING(roles,",")
  }

 

  SetHasRole=0
 
  ForRoleIdx=1:1:$LISTLENGTH(UserRoles){
    If$LISTFIND(RolesAllowed,$LIST(UserRoles,RoleIdx)){
      SetHasRole=1
      Quit
    }
  }

 

  IfHasRole{
    SetpAuthorized=1
  }Else{
    SetpAuthorized=0
    Setmessage.error=$USERNAME_" is not authorized for this request. User Roles Allowed is not in User Roles"
    Writemessage.%ToJSON()
  }

 

  ReturntSC
}

Se a regra corresponder, é setado pAuthorized = 1, caso contrário, é setado 0.

Agora, as funções permitidas são baseadas na configuração de XData para sua classe REST. Excelente!

Para meu novo app em ação vá em: https://openexchange.intersystems.com/package/API-Security-Mediator.