Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Vireo 3 to 4 migration script to map person.institutionalidentifier to user.netid #92

Open
wwelling opened this issue Jul 17, 2024 · 4 comments · Fixed by #93
Open

Vireo 3 to 4 migration script to map person.institutionalidentifier to user.netid #92

wwelling opened this issue Jul 17, 2024 · 4 comments · Fixed by #93
Assignees

Comments

@wwelling
Copy link

wwelling commented Jul 17, 2024

No description provided.

@wwelling
Copy link
Author

Here is a query to get all persons without UIN in Vireo 3 DB.

SELECT currentemailaddress as email, firstname, lastname, netid as identifier FROM person WHERE institutionalidentifier IS NULL

@wwelling
Copy link
Author

wwelling commented Jul 17, 2024

Here is a node.js script to update Vireo 4 weaver_users netid to be institutionalidentifier (UIN) from Vireo 3. If UIN not available, it will use netid (unique hash) or email.

// npm install pg
// mkdir logs
// node index.js > logs/index.log
const { Client } = require('pg');

const vireo4db = {
  user: process.env.VIREO4_DB_USER || 'vireo',
  host: process.env.VIREO4_DB_HOST || 'localhost',
  database: process.env.VIREO4_DB_NAME || 'vireo',
  password: process.env.VIREO4_DB_PASSWORD || 'vireo',
  port: process.env.VIREO4_DB_PORT || 5432,
};

const vireo3db = {
  user: process.env.VIREO3_DB_USER || 'etduser',
  host: process.env.VIREO3_DB_HOST || 'localhost',
  database: process.env.VIREO3_DB_NAME || 'vireo',
  password: process.env.VIREO3_DB_PASSWORD || 'etduser',
  port: process.env.VIREO3_DB_PORT || 5433,
};

async function queryDatabase(config, query) {
  const client = new Client(config);

  try {
    await client.connect();
    const res = await client.query(query);
    return res.rows;
  } catch (err) {
    console.log('Error querying database:', err);
  } finally {
    await client.end();
  }
}

async function updateDatabase(config, query, values) {
  const client = new Client(config);

  try {
    await client.connect();
    const res = await client.query(query, values);
    return res.rowCount;
  } catch (err) {
    console.log('Error updating database:', err);
  } finally {
    await client.end();
  }
}

async function main() {
  const selectQuery = 'SELECT coalesce(institutionalidentifier, netid, email) AS primary, coalesce(netid, email) AS secondary FROM person';
  const updateQuery = 'UPDATE weaver_users SET netid = $1 WHERE netid = $2 OR email = $2';

  try {
    for (const person of await queryDatabase(vireo3db, selectQuery)) {
      const rowsUpdated = await updateDatabase(vireo4db, updateQuery, [person.primary, person.secondary]);
      if (rowsUpdated) {
        console.log(`SUCCCESS: UPDATE weaver_users SET netid = ${person.primary} WHERE netid = ${person.secondary} OR email = ${person.secondary}`);
      } else {
        console.log(`FAILURE: UPDATE weaver_users SET netid = ${person.primary} WHERE netid = ${person.secondary} OR email = ${person.secondary}`);
      }
    }
  } catch (err) {
    console.log('Error during main execution:', err);
  }
}

main();

@wwelling wwelling linked a pull request Jul 17, 2024 that will close this issue
@wwelling wwelling changed the title Update Vireo 3 to 4 migration script to map person.institutionalidentifier to user.netid Vireo 3 to 4 migration script to map person.institutionalidentifier to user.netid Jul 17, 2024
@wwelling
Copy link
Author

wwelling commented Jul 19, 2024

A request ticket has been sent to the ID office to see if we can collect missing UIN for persons Vireo 3 that do not have one. The ticket number is INC2267838.

@wwelling
Copy link
Author

wwelling commented Jul 19, 2024

Here is a node.js script to request individual record from directory search ID office provides to retrieve UIN to update netid. However, we will have to get elevated permissions to get UIN in the response. If elevated permissions do not provide UIN in the responses for lookup by UID then not sure there is anything left to do for this issue.

https://docs.security.tamu.edu/docs/identity-security/attribute-services/api/directory_search/

// provide client identifier and shared secret
// npm install pg axios crypto
// mkdir logs
// node uin.js > logs/uin.log
const { Client } = require('pg');
const axios = require('axios');
const crypto = require('crypto');

const vireo4db = {
  user: process.env.VIREO4_DB_USER || 'vireo',
  host: process.env.VIREO4_DB_HOST || 'localhost',
  database: process.env.VIREO4_DB_NAME || 'vireo',
  password: process.env.VIREO4_DB_PASSWORD || 'vireo',
  port: process.env.VIREO4_DB_PORT || 5432,
};

const directoryClient = {
  identifier: process.env.CLIENT_IDENTIFIER || '',
  sharedSecret: process.env.CLIENT_SHARED_SECRET || '',
  throttleEvery: process.env.CLIENT_THROTTLE_EVERY || 10,
  throttleInMilliseconds: process.env.CLIENT_THROTTLE_IN_MILLISECONDS || 2000
}

async function queryDatabase(config, query) {
  const client = new Client(config);

  try {
    await client.connect();
    const res = await client.query(query);
    return res.rows;
  } catch (err) {
    console.log('Error querying database:', err);
  } finally {
    await client.end();
  }
}

async function updateDatabase(config, query, values) {
  const client = new Client(config);

  try {
    await client.connect(); 
    const res = await client.query(query, values);
    return res.rowCount;
  } catch (err) {
    console.log('Error updating database:', err);
  } finally {
    await client.end();
  }
}

async function getPerson(netid) {
  const api = netid.length === 32 ? 'uid' : 'netid';
  const requestUri = `/rest/directory/${api}/${netid}/json/`;
  const baseUrl = 'https://mqs.tamu.edu';
  const url = baseUrl + requestUri;
  const date = new Date().toUTCString();

  const authenticationString = `${requestUri}\n${date}\n${directoryClient.identifier}`;

  const signature = crypto
    .createHmac('sha256', directoryClient.sharedSecret)
    .update(authenticationString)
    .digest('base64');

  const authorizationHeader = `TAM ${directoryClient.identifier}:${signature}`;

  try {
    console.log(url);
    const response = await axios.get(url, {
      headers: {
        'Authorization': authorizationHeader,
        'Date': date
      }
    });
    return response.data;
  } catch (error) {
    console.log('Error making request:', error);
  }
}

async function sleep(ms) {
  return new Promise(resolve => setTimeout(resolve, ms));
}

async function main() {
  const selectQuery = 'SELECT netid FROM weaver_users WHERE length(netid) != 9 AND netid !~ \'^\\d+$\'';
  const updateQuery = 'UPDATE weaver_users SET netid = $1 WHERE netid = $2';

  try {
    let i = 0;
    for (const user of await queryDatabase(vireo4db, selectQuery)) {
      console.log(user);
      if (user.netid.indexOf('@') >= 0) {
        continue;
      }
      const person = await getPerson(user.netid);
      console.log(person);
      if (person.tamuEduPersonUIN && person.tamuEduPersonUIN.length > 0) {
        const uin = person.tamuEduPersonUIN[0]
        const rowsUpdated = await updateDatabase(vireo4db, updateQuery, [uin, user.netid]);
        if (rowsUpdated) {
          console.log(`SUCCCESS: UPDATE weaver_users SET netid = ${uin} WHERE netid = ${user.netid}`);
        } else {
          console.log(`FAILURE: UPDATE weaver_users SET netid = ${uin} WHERE netid = ${user.netid}`);
        }
      }
      i++;
      if (i % directoryClient.throttleEvery == 0) {
        await sleep(directoryClient.throttleInMilliseconds);
      }
    }
  } catch (err) {
    console.log('Error during main execution:', err);
  }
}

main();

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants