actions.js 7.8 KB
Newer Older
1
import parseUrl from "url-parse"
R
Ron 已提交
2
import win from "core/window"
3
import { btoa, buildFormData } from "core/utils"
R
Ron 已提交
4 5 6 7 8 9 10

export const SHOW_AUTH_POPUP = "show_popup"
export const AUTHORIZE = "authorize"
export const LOGOUT = "logout"
export const PRE_AUTHORIZE_OAUTH2 = "pre_authorize_oauth2"
export const AUTHORIZE_OAUTH2 = "authorize_oauth2"
export const VALIDATE = "validate"
11
export const CONFIGURE_AUTH = "configure_auth"
12
export const RESTORE_AUTHORIZATION = "restore_authorization"
R
Ron 已提交
13

14 15
const scopeSeparator = " "

R
Ron 已提交
16 17 18 19 20 21 22 23 24 25 26 27 28 29
export function showDefinitions(payload) {
  return {
    type: SHOW_AUTH_POPUP,
    payload: payload
  }
}

export function authorize(payload) {
  return {
    type: AUTHORIZE,
    payload: payload
  }
}

30 31 32 33 34
export const authorizeWithPersistOption = (payload) => ( { authActions } ) => {
  authActions.authorize(payload)
  authActions.persistAuthorizationIfNeeded()  
}

R
Ron 已提交
35 36 37 38 39 40 41
export function logout(payload) {
  return {
    type: LOGOUT,
    payload: payload
  }
}

42 43 44 45 46
export const logoutWithPersistOption = (payload) => ( { authActions } ) => {
  authActions.logout(payload)
  authActions.persistAuthorizationIfNeeded()  
}

A
Anna Bodnia 已提交
47
export const preAuthorizeImplicit = (payload) => ( { authActions, errActions } ) => {
R
Ron 已提交
48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73
  let { auth , token, isValid } = payload
  let { schema, name } = auth
  let flow = schema.get("flow")

  // remove oauth2 property from window after redirect from authentication
  delete win.swaggerUIRedirectOauth2

  if ( flow !== "accessCode" && !isValid ) {
    errActions.newAuthErr( {
      authId: name,
      source: "auth",
      level: "warning",
      message: "Authorization may be unsafe, passed state was changed in server Passed state wasn't returned from auth server"
    })
  }

  if ( token.error ) {
    errActions.newAuthErr({
      authId: name,
      source: "auth",
      level: "error",
      message: JSON.stringify(token)
    })
    return
  }

74
  authActions.authorizeOauth2WithPersistOption({ auth, token })
R
Ron 已提交
75 76
}

77

R
Ron 已提交
78 79 80 81 82 83 84
export function authorizeOauth2(payload) {
  return {
    type: AUTHORIZE_OAUTH2,
    payload: payload
  }
}

85 86 87 88 89 90

export const authorizeOauth2WithPersistOption = (payload) => ( { authActions } ) => {
  authActions.authorizeOauth2(payload)
  authActions.persistAuthorizationIfNeeded()  
}

A
Anna Bodnia 已提交
91
export const authorizePassword = ( auth ) => ( { authActions } ) => {
R
Ron 已提交
92
  let { schema, name, username, password, passwordType, clientId, clientSecret } = auth
A
Anna Bodnia 已提交
93
  let form = {
94
    grant_type: "password",
95 96 97
    scope: auth.scopes.join(scopeSeparator),
    username,
    password
98
  }
A
Anna Bodnia 已提交
99 100
  let query = {}
  let headers = {}
R
Ron 已提交
101

102 103 104 105
  switch (passwordType) {
    case "request-body":
      setClientIdAndSecret(form, clientId, clientSecret)
      break
106

107 108 109 110 111
    case "basic":
      headers.Authorization = "Basic " + btoa(clientId + ":" + clientSecret)
      break
    default:
      console.warn(`Warning: invalid passwordType ${passwordType} was passed, not including client id and secret`)
R
Ron 已提交
112
  }
A
Anna Bodnia 已提交
113 114 115 116

  return authActions.authorizeRequest({ body: buildFormData(form), url: schema.get("tokenUrl"), name, headers, query, auth})
}

117 118 119 120 121 122 123 124 125 126
function setClientIdAndSecret(target, clientId, clientSecret) {
  if ( clientId ) {
    Object.assign(target, {client_id: clientId})
  }

  if ( clientSecret ) {
    Object.assign(target, {client_secret: clientSecret})
  }
}

A
Anna Bodnia 已提交
127
export const authorizeApplication = ( auth ) => ( { authActions } ) => {
A
Anna Bodnia 已提交
128
  let { schema, scopes, name, clientId, clientSecret } = auth
A
Anna Bodnia 已提交
129 130 131
  let headers = {
    Authorization: "Basic " + btoa(clientId + ":" + clientSecret)
  }
A
Anna Bodnia 已提交
132 133 134 135 136
  let form = {
    grant_type: "client_credentials",
    scope: scopes.join(scopeSeparator)
  }

A
Anna Bodnia 已提交
137
  return authActions.authorizeRequest({body: buildFormData(form), name, url: schema.get("tokenUrl"), auth, headers })
A
Anna Bodnia 已提交
138 139
}

140
export const authorizeAccessCodeWithFormParams = ( { auth, redirectUrl } ) => ( { authActions } ) => {
141
  let { schema, name, clientId, clientSecret, codeVerifier } = auth
142 143 144 145 146
  let form = {
    grant_type: "authorization_code",
    code: auth.code,
    client_id: clientId,
    client_secret: clientSecret,
147 148
    redirect_uri: redirectUrl,
    code_verifier: codeVerifier
149
  }
A
Anna Bodnia 已提交
150

151
  return authActions.authorizeRequest({body: buildFormData(form), name, url: schema.get("tokenUrl"), auth})
A
Anna Bodnia 已提交
152 153
}

154 155 156 157 158 159 160 161 162 163 164 165 166 167 168
export const authorizeAccessCodeWithBasicAuthentication = ( { auth, redirectUrl } ) => ( { authActions } ) => {
  let { schema, name, clientId, clientSecret } = auth
  let headers = {
    Authorization: "Basic " + btoa(clientId + ":" + clientSecret)
  }
  let form = {
    grant_type: "authorization_code",
    code: auth.code,
    client_id: clientId,
    redirect_uri: redirectUrl
  }

  return authActions.authorizeRequest({body: buildFormData(form), name, url: schema.get("tokenUrl"), auth, headers})
}

169
export const authorizeRequest = ( data ) => ( { fn, getConfigs, authActions, errActions, oas3Selectors, specSelectors, authSelectors } ) => {
A
Anna Bodnia 已提交
170
  let { body, query={}, headers={}, name, url, auth } = data
171

172 173 174
  let { additionalQueryStringParams } = authSelectors.getConfigs() || {}

  let parsedUrl
175 176

  if (specSelectors.isOAS3()) {
177 178
    let finalServerUrl = oas3Selectors.serverEffectiveValue(oas3Selectors.selectedServer())
    parsedUrl = parseUrl(url, finalServerUrl, true)
179
  } else {
180 181 182 183 184
    parsedUrl = parseUrl(url, specSelectors.url(), true)
  }

  if(typeof additionalQueryStringParams === "object") {
    parsedUrl.query = Object.assign({}, parsedUrl.query, additionalQueryStringParams)
185
  }
A
Anna Bodnia 已提交
186

187 188
  const fetchUrl = parsedUrl.toString()

A
Anna Bodnia 已提交
189 190
  let _headers = Object.assign({
    "Accept":"application/json, text/plain, */*",
191 192
    "Content-Type": "application/x-www-form-urlencoded",
    "X-Requested-With": "XMLHttpRequest"
A
Anna Bodnia 已提交
193 194 195
  }, headers)

  fn.fetch({
196
    url: fetchUrl,
A
Anna Bodnia 已提交
197 198 199
    method: "post",
    headers: _headers,
    query: query,
200
    body: body,
K
Kyle Shockey 已提交
201 202
    requestInterceptor: getConfigs().requestInterceptor,
    responseInterceptor: getConfigs().responseInterceptor
A
Anna Bodnia 已提交
203
  })
204 205 206 207
  .then(function (response) {
    let token = JSON.parse(response.data)
    let error = token && ( token.error || "" )
    let parseError = token && ( token.parseError || "" )
R
Ron 已提交
208

209
    if ( !response.ok ) {
A
Anna Bodnia 已提交
210 211 212 213
      errActions.newAuthErr( {
        authId: name,
        level: "error",
        source: "auth",
214 215 216 217 218 219 220 221 222 223 224 225 226 227 228
        message: response.statusText
      } )
      return
    }

    if ( error || parseError ) {
      errActions.newAuthErr({
        authId: name,
        level: "error",
        source: "auth",
        message: JSON.stringify(token)
      })
      return
    }

229
    authActions.authorizeOauth2WithPersistOption({ auth, token})
230 231 232
  })
  .catch(e => {
    let err = new Error(e)
233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249
    let message = err.message
    // swagger-js wraps the response (if available) into the e.response property;
    // investigate to check whether there are more details on why the authorization
    // request failed (according to RFC 6479).
    // See also https://github.com/swagger-api/swagger-ui/issues/4048
    if (e.response && e.response.data) {
      const errData = e.response.data
      try {
        const jsonResponse = typeof errData === "string" ? JSON.parse(errData) : errData
        if (jsonResponse.error)
          message += `, error: ${jsonResponse.error}`
        if (jsonResponse.error_description)
          message += `, description: ${jsonResponse.error_description}`
      } catch (jsonError) {
        // Ignore
      }
    }
250 251 252 253
    errActions.newAuthErr( {
      authId: name,
      level: "error",
      source: "auth",
254
      message: message
255 256
    } )
  })
R
Ron 已提交
257
}
258 259 260 261 262 263 264

export function configureAuth(payload) {
  return {
    type: CONFIGURE_AUTH,
    payload: payload
  }
}
265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280

export function restoreAuthorization(payload) {
  return {
    type: RESTORE_AUTHORIZATION,
    payload: payload
  }
}

export const persistAuthorizationIfNeeded = () => ( { authSelectors, getConfigs } ) => {
  const configs = getConfigs()
  if (configs.persistAuthorization)
  {
    const authorized = authSelectors.authorized()
    localStorage.setItem("authorized", JSON.stringify(authorized.toJS()))
  }
}